mirror of https://github.com/BOINC/boinc.git
Drupal: Added context module to list of contrib/ modules.
Change version number by adding suffix boinc-1-dev. https://dev.gridrepublic.org/browse/DBOINCP-489
This commit is contained in:
parent
b794796ecd
commit
d627580389
|
@ -0,0 +1,81 @@
|
|||
|
||||
Context 3.x API
|
||||
---------------
|
||||
The following is an overview of using the Context API.
|
||||
|
||||
|
||||
The context static cache
|
||||
------------------------
|
||||
Context provides a centralized set of API functions for setting and retrieving a
|
||||
static cache:
|
||||
|
||||
// Set a static cache value at [my_namspace][mykey]
|
||||
context_set('my_namespace', 'mykey', $value);
|
||||
|
||||
// Retrieve a static cache value at [my_namespace][mykey]
|
||||
context_get('my_namespace', 'mykey'); // $value
|
||||
|
||||
// Boolean for whether there is a value at [my_namespace][mykey]
|
||||
context_isset('my_namespace', 'mykey'); // TRUE
|
||||
|
||||
These are used internally by context but may also be used by other modules. Just
|
||||
do not use the namespace `context` unless you want to affect things that context
|
||||
is up to.
|
||||
|
||||
|
||||
Adding a condition or reaction plugin
|
||||
-------------------------------------
|
||||
Both context conditions and reactions utilize the CTools plugins API. In order
|
||||
to add a new condition or reaction for your module, follow these steps:
|
||||
|
||||
1. Implement `hook_context_plugins()` to define your plugins, classes, and class
|
||||
hierarchy.
|
||||
|
||||
function mymodule_context_plugins() {
|
||||
$plugins = array();
|
||||
$plugins['mymodule_context_condition_bar'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'mymodule') .'/plugins',
|
||||
'file' => 'mymodule_context_condition_bar.inc',
|
||||
'class' => 'mymodule_context_condition_bar',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
2. Implement `hook_context_registry()` to define your conditions and/or
|
||||
reactions and map them to plugins.
|
||||
|
||||
function mymodule_context_registry() {
|
||||
return array(
|
||||
'conditions' => array(
|
||||
'bar' => array(
|
||||
'title' => t('Name of condition "bar"'),
|
||||
'plugin' => 'mymodule_context_condition_bar',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
3. Write your condition or reaction plugin class. It's best to look at one of
|
||||
the included plugins as a starting point.
|
||||
|
||||
4. Add in a Drupal integration point for your plugin. A node page condition
|
||||
plugin, for example, may be invoked from `hook_nodeapi()`.
|
||||
|
||||
|
||||
Replacing or extending existing plugins
|
||||
---------------------------------------
|
||||
You can replace a condition or reaction plugin with your own plugin class using
|
||||
`hook_context_registry_alter()`:
|
||||
|
||||
function mymodule_context_registry_alter(&$registry) {
|
||||
if (!empty($registry['conditions']['node'])) {
|
||||
$registry['conditions']['node']['plugin'] = 'mymodule_context_condition_customnode';
|
||||
}
|
||||
}
|
||||
|
||||
This entry would swap out the default node condition plugin for a custom one
|
||||
provided by `mymodule`. Note that any replacement plugins must have an entry in
|
||||
`hook_context_plugins()`.
|
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
Context 3.x for Drupal 6.x
|
||||
--------------------------
|
||||
Context allows you to manage contextual conditions and reactions for
|
||||
different portions of your site. You can think of each context as
|
||||
representing a "section" of your site. For each context, you can choose
|
||||
the conditions that trigger this context to be active and choose different
|
||||
aspects of Drupal that should react to this active context.
|
||||
|
||||
Think of conditions as a set of rules that are checked during page load
|
||||
to see what context is active. Any reactions that are associated with
|
||||
active contexts are then fired.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
Context can be installed like any other Drupal module -- place it in
|
||||
the modules directory for your site and enable it (and its requirement,
|
||||
CTools) on the `admin/build/modules` page.
|
||||
|
||||
You will probably also want to install Context UI which provides a way for
|
||||
you to edit contexts through the Drupal admin interface.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
You want to create a "pressroom" section of your site. You have a press
|
||||
room view that displays press release nodes, but you also want to tie
|
||||
a book with media resources tightly to this section. You would also
|
||||
like a contact block you've made to appear whenever a user is in the
|
||||
pressroom section.
|
||||
|
||||
1. Add a new context on admin/build/context
|
||||
2. Under "Conditions", associate the pressroom nodetype, the pressroom view,
|
||||
and the media kit book with the context.
|
||||
3. Under "Reactions > Menu", choose the pressroom menu item to be set active.
|
||||
4. Under "Reactions > Blocks", add the contact block to a region.
|
||||
5. Save the context.
|
||||
|
||||
For a more in-depth overview of the UI components, see the Context UI
|
||||
`README.txt`.
|
||||
|
||||
|
||||
Upgrading from Context 2.x for Drupal 6.x
|
||||
-----------------------------------------
|
||||
- Download latest Context 3.x and latest CTools release and place in modules
|
||||
directory. Make sure to *remove* the existing Context 2.x directory before
|
||||
unpacking Context 3.x. There are stale files in the 2.x branch that need to
|
||||
be removed.
|
||||
- Run `update.php` or `drush updatedb`.
|
||||
- If your site contains contexts defined in code they will be overridden.
|
||||
Re-export them to code again. If you are using any custom conditions or
|
||||
reactions, you may need to upgrade or reconfigure them by hand. See `API.txt`
|
||||
for instructions on adding and extending plugins in Context.
|
||||
|
||||
|
||||
Hooks
|
||||
-----
|
||||
See `context.api.php` for the hooks made available by context and `API.txt` for
|
||||
usage examples.
|
||||
|
||||
|
||||
Maintainers
|
||||
-----------
|
||||
|
||||
- yhahn (Young Hahn)
|
||||
- jmiccolis (Jeff Miccolis)
|
||||
- Steven Jones
|
||||
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
- alex_b (Alex Barth)
|
||||
- dmitrig01 (Dmitri Gaskin)
|
||||
- Pasqualle (Csuthy Bálint)
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided by Context.
|
||||
*/
|
||||
|
||||
/**
|
||||
* CTools plugin API hook for Context. Note that a proper entry in
|
||||
* hook_ctools_plugin_api() must exist for this hook to be called.
|
||||
*/
|
||||
function hook_context_plugins() {
|
||||
$plugins = array();
|
||||
$plugins['foo_context_condition_bar'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'foo') .'/plugins',
|
||||
'file' => 'foo_context_condition_bar.inc',
|
||||
'class' => 'foo_context_condition_bar',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
$plugins['foo_context_reaction_baz'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'foo') .'/plugins',
|
||||
'file' => 'foo_context_reaction_baz.inc',
|
||||
'class' => 'foo_context_reaction_baz',
|
||||
'parent' => 'context_reaction',
|
||||
),
|
||||
);
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registry hook for conditions & reactions.
|
||||
*
|
||||
* Each entry associates a condition or reaction with the CTools plugin to be
|
||||
* used as its plugin class.
|
||||
*/
|
||||
function hook_context_registry() {
|
||||
return array(
|
||||
'conditions' => array(
|
||||
'bar' => array(
|
||||
'title' => t('Name of condition "bar"'),
|
||||
'plugin' => 'foo_context_condition_bar',
|
||||
),
|
||||
),
|
||||
'reactions' => array(
|
||||
'baz' => array(
|
||||
'title' => t('Name of reaction "baz"'),
|
||||
'plugin' => 'foo_context_reaction_baz',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the registry.
|
||||
*
|
||||
* Allows modules to alter the registry. Default plugins can be replaced by
|
||||
* custom ones declared in hook_context_plugins().
|
||||
*
|
||||
* @param $registry
|
||||
* The registry, passed by reference.
|
||||
*/
|
||||
function hook_context_registry_alter(&$registry) {
|
||||
if (isset($registry['reactions']['baz'])) {
|
||||
$registry['reactions']['baz']['plugin'] = 'custom_context_reaction_baz';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter/add a condition to a node-related event.
|
||||
*
|
||||
* Allows modules to add one or more context condition plugin executions to a
|
||||
* node view, form, etc.
|
||||
*
|
||||
* @param $node
|
||||
* The node object.
|
||||
* @param $op
|
||||
* The node-related operation: 'node', 'form', 'comment'.
|
||||
*/
|
||||
function hook_context_node_condition_alter(&$node, $op) {
|
||||
if ($plugin = context_get_plugin('condition', 'bar')) {
|
||||
$plugin->execute($node, $op);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter a context directly after it has been loaded. Allows modules to alter
|
||||
* a context object's reactions. While you may alter conditions, this will
|
||||
* generally have no effect as conditions are cached for performance and
|
||||
* contexts are loaded after conditions are checked, not before.
|
||||
*
|
||||
* @param &$context
|
||||
* The context object by reference.
|
||||
*/
|
||||
function hook_context_load_alter(&$context) {
|
||||
if ($context->name === 'foo' && isset($context->reactions['block'])) {
|
||||
$context->reactions['block']['blocks']['locale-0'] = array(
|
||||
'module' => 'locale',
|
||||
'delta' => '0',
|
||||
'region' => 'header',
|
||||
'weight' => '2',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows for finer grained access mechanisms to using the json
|
||||
* rendering capabilities of the block reaction when a user isn't
|
||||
* granted the administer contexts or context ajax block access
|
||||
* permission
|
||||
* @param $block_id
|
||||
* ID of block in module-delta format
|
||||
*/
|
||||
function hook_context_allow_ajax_block_access($block_id) {
|
||||
}
|
|
@ -0,0 +1,335 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implementation of hook_help().
|
||||
*/
|
||||
function context_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#context':
|
||||
$output = file_get_contents(drupal_get_path('module', 'context') .'/README.txt');
|
||||
return module_exists('markdown') ? filter_xss_admin(module_invoke('markdown', 'filter', 'process', 0, -1, $output)) : '<pre>'. check_plain($output) .'</pre>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_menu_alter().
|
||||
* If core block handling is disabled, remove menu items.
|
||||
*/
|
||||
function context_menu_alter(&$items) {
|
||||
if (variable_get('context_reaction_block_disable_core', FALSE)) {
|
||||
foreach ($items as $path => $item) {
|
||||
if (strpos($path, 'admin/build/block') === 0) {
|
||||
unset($items[$path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_theme().
|
||||
*/
|
||||
function context_theme() {
|
||||
$items = array();
|
||||
$items['context_block_form'] = array(
|
||||
'arguments' => array('form' => array()),
|
||||
'path' => drupal_get_path('module', 'context') . '/theme',
|
||||
'file' => 'context_reaction_block.theme.inc',
|
||||
);
|
||||
$items['context_block_regions_form'] = array(
|
||||
'arguments' => array('form' => array()),
|
||||
'path' => drupal_get_path('module', 'context') . '/theme',
|
||||
'file' => 'context_reaction_block.theme.inc',
|
||||
);
|
||||
$items['context_block_editor'] = array(
|
||||
'arguments' => array('form' => array()),
|
||||
'path' => drupal_get_path('module', 'context') . '/theme',
|
||||
'file' => 'context_reaction_block.theme.inc',
|
||||
);
|
||||
$items['context_block_browser'] = array(
|
||||
'arguments' => array('blocks' => array(), 'context' => array()),
|
||||
'path' => drupal_get_path('module', 'context') . '/theme',
|
||||
'template' => 'context-block-browser',
|
||||
'file' => 'context_reaction_block.theme.inc',
|
||||
);
|
||||
$items['context_block_browser_item'] = array(
|
||||
'arguments' => array('block' => array()),
|
||||
'path' => drupal_get_path('module', 'context') . '/theme',
|
||||
'template' => 'context-block-browser-item',
|
||||
'file' => 'context_reaction_block.theme.inc',
|
||||
);
|
||||
$items['context_block_editable_block'] = array(
|
||||
'arguments' => array('block' => array()),
|
||||
'path' => drupal_get_path('module', 'context') . '/theme',
|
||||
'template' => 'context-block-editable-block',
|
||||
'file' => 'context_reaction_block.theme.inc',
|
||||
);
|
||||
$items['context_block_editable_region'] = array(
|
||||
'arguments' => array('region' => '', 'blocks' => array(), 'editable' => FALSE),
|
||||
'path' => drupal_get_path('module', 'context') . '/theme',
|
||||
'template' => 'context-block-editable-region',
|
||||
'file' => 'context_reaction_block.theme.inc',
|
||||
);
|
||||
$items['context_block_script_placeholder'] = array(
|
||||
'arguments' => array('text' => NULL),
|
||||
'path' => drupal_get_path('module', 'context') . '/theme',
|
||||
'file' => 'context_reaction_block.theme.inc',
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_theme_registry_alter().
|
||||
*/
|
||||
function context_theme_registry_alter(&$theme_registry) {
|
||||
// Push theme_page() through a context_preprocess to provide
|
||||
// context-sensitive menus and variables. Ensure that
|
||||
// context_preprocess_page() comes immediately after
|
||||
// template_preprocess_page().
|
||||
$position = array_search('context_preprocess_page', $theme_registry['page']['preprocess functions']);
|
||||
if ($position !== FALSE) {
|
||||
unset($theme_registry['page']['preprocess functions'][$position]);
|
||||
}
|
||||
$position = array_search('template_preprocess_page', $theme_registry['page']['preprocess functions']);
|
||||
$position = $position ? $position + 1 : 2;
|
||||
array_splice($theme_registry['page']['preprocess functions'], $position, 0, 'context_preprocess_page');
|
||||
|
||||
// Add a page preprocess function to the very top of the theme_page()
|
||||
// stack so that we can actually set contexts *before* the page theming
|
||||
// is executed.
|
||||
if (!in_array('context_page_alter', $theme_registry['page']['preprocess functions'])) {
|
||||
array_unshift($theme_registry['page']['preprocess functions'], 'context_page_alter');
|
||||
}
|
||||
// Reroute theme_blocks() through context_blocks to determine block
|
||||
// visibility by context. Only override theme_blocks() if a theme
|
||||
// has not overridden it. It is the responsibility of any themes
|
||||
// implementing theme_blocks() to take advantage of context block
|
||||
// visibility on their own.
|
||||
if (!isset($theme_registry['blocks']['type']) || !in_array($theme_registry['blocks']['type'], array('base_theme_engine', 'theme_engine')) && !isset($theme_registry['blocks']['file'])) {
|
||||
unset($theme_registry['blocks']['preprocess functions']);
|
||||
$theme_registry['blocks']['function'] = 'context_blocks';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_ctools_render_alter().
|
||||
* Used to detect the presence of a page manager node view or node form.
|
||||
*/
|
||||
function context_ctools_render_alter($info, $page, $args, $contexts, $task, $subtask) {
|
||||
if ($page && in_array($task['name'], array('node_view', 'node_edit'), TRUE)) {
|
||||
foreach ($contexts as $ctools_context) {
|
||||
if ($ctools_context->type === 'node' && !empty($ctools_context->data)) {
|
||||
context_node_condition($ctools_context->data, $task['name'] === 'node_view' ? 'view' : 'form');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_nodeapi().
|
||||
*/
|
||||
function context_nodeapi(&$node, $op, $teaser, $page) {
|
||||
if ($op == 'view' && $page) {
|
||||
$object = menu_get_object();
|
||||
if (isset($object->nid) && $object->nid === $node->nid) {
|
||||
context_node_condition($node, 'view');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_form_alter().
|
||||
*/
|
||||
function context_form_alter(&$form, $form_state, $form_id) {
|
||||
// Prevent this from firing on admin pages... damn form driven apis...
|
||||
if ($form['#id'] === 'node-form' && arg(0) != 'admin') {
|
||||
context_node_condition($form['#node'], 'form');
|
||||
$form['#validate'][] = 'context_form_alter_node_validate';
|
||||
}
|
||||
else if ($form_id == 'system_modules') {
|
||||
context_invalidate_cache();
|
||||
}
|
||||
// Clear out block info cache when an admin area form is submitted.
|
||||
if (arg(0) === 'admin' && !empty($form_state['post']) && (!isset($form_state['method']) || $form_state['method'] !== 'get')) {
|
||||
if ($plugin = context_get_plugin('reaction', 'block')) {
|
||||
$plugin->rebuild_needed(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralized node condition call function for the ever increasing number of
|
||||
* ways to get at a node view / node form.
|
||||
*/
|
||||
function context_node_condition(&$node, $op) {
|
||||
if ($plugin = context_get_plugin('condition', 'node')) {
|
||||
$plugin->execute($node, $op);
|
||||
}
|
||||
if (module_exists('taxonomy')) {
|
||||
if ($plugin = context_get_plugin('condition', 'node_taxonomy')) {
|
||||
$plugin->execute($node, $op);
|
||||
}
|
||||
}
|
||||
if (module_exists('book')) {
|
||||
if ($plugin = context_get_plugin('condition', 'book')) {
|
||||
$plugin->execute($node, $op);
|
||||
}
|
||||
if ($plugin = context_get_plugin('condition', 'bookroot')) {
|
||||
$plugin->execute($node, $op);
|
||||
}
|
||||
}
|
||||
// Allow other plugins to easily be triggered on node-related events.
|
||||
drupal_alter('context_node_condition', $node, $op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Node form validation callback.
|
||||
*
|
||||
* Set context also on validate, otherwise forms that don't validate drop out
|
||||
* of context.
|
||||
*/
|
||||
function context_form_alter_node_validate($form, &$form_state) {
|
||||
context_node_condition($form['#node'], 'form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_form_alter() for comment_form.
|
||||
*/
|
||||
function context_form_comment_form_alter(&$form, $form_state) {
|
||||
if ($nid = $form['nid']['#value']) {
|
||||
$node = node_load($nid);
|
||||
context_node_condition($node, 'comment');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_views_pre_view().
|
||||
*/
|
||||
function context_views_pre_view($view, $args) {
|
||||
if ($plugin = context_get_plugin('condition', 'views')) {
|
||||
$plugin->execute($view);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_user().
|
||||
*/
|
||||
function context_user($op, &$edit, &$account, $category = NULL) {
|
||||
if (in_array($op, array('view', 'form', 'register'))) {
|
||||
if ($plugin = context_get_plugin('condition', 'user_page')) {
|
||||
$plugin->execute($account, $op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BLOCK HANDLING =====================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* This override of theme_blocks() is called because of an alter of the
|
||||
* theme registry. See context_theme_registry_alter().
|
||||
*/
|
||||
function context_blocks($region) {
|
||||
if ($plugin = context_get_plugin('reaction', 'block')) {
|
||||
return $plugin->execute($region);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* THEME FUNCTIONS & RELATED ==========================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates an array of links (suitable for use with theme_links)
|
||||
* to the node forms of types associated with current active contexts.
|
||||
*/
|
||||
function context_links($reset = FALSE) {
|
||||
static $links;
|
||||
if (!$links || $reset) {
|
||||
$contexts = context_active_contexts();
|
||||
$active_types = array();
|
||||
$conditions = array('node', 'bookroot');
|
||||
foreach ($conditions as $condition) {
|
||||
foreach ($contexts as $k => $v) {
|
||||
if (!empty($v->conditions[$condition]['values'])) {
|
||||
$active_types = array_merge($active_types, array_filter($v->conditions[$condition]['values']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$links = array();
|
||||
if (!empty($active_types)) {
|
||||
// Iterate over active contexts
|
||||
foreach ($active_types as $type) {
|
||||
$add_url = 'node/add/'. str_replace('_', '-', $type);
|
||||
$item = menu_get_item($add_url);
|
||||
if ($item && $item['access'] && strpos($_GET['q'], $add_url) !== 0) {
|
||||
$links[$type] = array('title' => t('Add @type', array('@type' => node_get_types('name', $type))), 'href' => $add_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
drupal_alter('context_links', $links);
|
||||
uasort($links, 'element_sort');
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* A preprocess_page() function that is called *before* all other
|
||||
* preprocessors (including template_preprocess_page()). This allows
|
||||
* any final context conditions to be set and any initial reactions
|
||||
* to be triggered.
|
||||
*/
|
||||
function context_page_alter(&$vars) {
|
||||
module_invoke_all('context_page_condition');
|
||||
module_invoke_all('context_page_reaction');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_context_page_condition().
|
||||
*/
|
||||
function context_context_page_condition() {
|
||||
if ($plugin = context_get_plugin('condition', 'menu')) {
|
||||
$plugin->execute();
|
||||
}
|
||||
if ($plugin = context_get_plugin('condition', 'sitewide')) {
|
||||
$plugin->execute(1);
|
||||
}
|
||||
if ($plugin = context_get_plugin('condition', 'context')) {
|
||||
$plugin->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_context_page_reaction().
|
||||
*/
|
||||
function context_context_page_reaction() {
|
||||
if ($plugin = context_get_plugin('reaction', 'breadcrumb')) {
|
||||
$plugin->execute();
|
||||
}
|
||||
if ($plugin = context_get_plugin('reaction', 'css_injector')) {
|
||||
$plugin->execute();
|
||||
}
|
||||
if ($plugin = context_get_plugin('reaction', 'debug')) {
|
||||
$plugin->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of preprocess_page().
|
||||
*/
|
||||
function context_preprocess_page(&$vars) {
|
||||
if ($plugin = context_get_plugin('reaction', 'menu')) {
|
||||
$plugin->execute($vars);
|
||||
}
|
||||
if ($plugin = context_get_plugin('reaction', 'theme')) {
|
||||
$plugin->execute($vars);
|
||||
}
|
||||
if ($context_links = context_links()) {
|
||||
$vars['context_links'] = theme('links', $context_links);
|
||||
}
|
||||
else {
|
||||
$vars['context_links'] = '';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
name = "Context"
|
||||
dependencies[] = "ctools"
|
||||
description = "Provide modules with a cache that lasts for a single page request."
|
||||
package = "Context"
|
||||
core = "6.x"
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-10-17
|
||||
version = "6.x-3.3-boinc-1-dev"
|
||||
core = "6.x"
|
||||
project = "context"
|
||||
datestamp = "1551298073"
|
||||
|
|
@ -0,0 +1,379 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of hook_requirements().
|
||||
*/
|
||||
function context_requirements($phase) {
|
||||
$requirements = array();
|
||||
$t = get_t();
|
||||
// Test PHP version
|
||||
if (!function_exists('json_decode')) {
|
||||
$requirements['php_context']['description'] = $t('Your PHP installation is too old. Context requires at least PHP %version or installation of the json library (%path)', array('%version' => '5.1.0', '%path' => 'http://pecl.php.net/package/json'));
|
||||
$requirements['php_context']['severity'] = REQUIREMENT_ERROR;
|
||||
}
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_install().
|
||||
*/
|
||||
function context_install() {
|
||||
drupal_install_schema('context');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_uninstall().
|
||||
*/
|
||||
function context_uninstall() {
|
||||
drupal_uninstall_schema('context');
|
||||
variable_del('context_ui_show_empty_regions');
|
||||
variable_del('context_reaction_block_disable_core');
|
||||
variable_del('context_reaction_block_all_regions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_schema().
|
||||
*/
|
||||
function context_schema() {
|
||||
$schema = array();
|
||||
$schema['context'] = array(
|
||||
'description' => 'Storage for normal (user-defined) contexts.',
|
||||
'export' => array(
|
||||
'key' => 'name',
|
||||
'identifier' => 'context',
|
||||
'default hook' => 'context_default_contexts', // Function hook name.
|
||||
'status' => 'context_status',
|
||||
'api' => array(
|
||||
'owner' => 'context',
|
||||
'api' => 'context', // Base name for api include files.
|
||||
'minimum_version' => 3,
|
||||
'current_version' => 3,
|
||||
),
|
||||
'export callback' => 'context_export',
|
||||
),
|
||||
'fields' => array(
|
||||
'name' => array(
|
||||
'description' => 'The primary identifier for a context.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'description' => array(
|
||||
'description' => 'Description for this context.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'tag' => array(
|
||||
'description' => 'Tag for this context.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'conditions' => array(
|
||||
'description' => 'Serialized storage of all context condition settings.',
|
||||
'type' => 'text',
|
||||
'serialize' => TRUE,
|
||||
),
|
||||
'reactions' => array(
|
||||
'description' => 'Serialized storage of all context reaction settings.',
|
||||
'type' => 'text',
|
||||
'serialize' => TRUE,
|
||||
),
|
||||
'condition_mode' => array(
|
||||
'description' => 'Condition mode for this context.',
|
||||
'type' => 'int',
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'primary key' => array('name'),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update script for context that installs the context schema and migrates
|
||||
* any existing context data from deprecated context_ui tables.
|
||||
*/
|
||||
function context_update_6001() {
|
||||
$ret = array();
|
||||
|
||||
if (!db_table_exists('context')) {
|
||||
drupal_install_schema('context');
|
||||
}
|
||||
|
||||
if (db_table_exists('context_ui')) {
|
||||
// Clear the schema cache and rebuild
|
||||
drupal_get_schema(NULL, TRUE);
|
||||
|
||||
// Migrate existing contexts to context table
|
||||
$result = db_query("SELECT * FROM {context_ui}");
|
||||
while ($context = db_fetch_object($result)) {
|
||||
// Load setters
|
||||
$setter_result = db_query("SELECT * FROM {context_ui_setter} WHERE cid = %d", $context->cid);
|
||||
while ($row = db_fetch_object($setter_result)) {
|
||||
$context->{$row->type}[$row->id] = $row->id;
|
||||
}
|
||||
// Load getters
|
||||
$getter_result = db_query("SELECT * FROM {context_ui_getter} WHERE cid = %d", $context->cid);
|
||||
while ($row = db_fetch_object($getter_result)) {
|
||||
$context->{$row->type} = unserialize($row->data);
|
||||
}
|
||||
// Load blocks
|
||||
$block_result = db_query("SELECT module, delta, region, weight FROM {context_ui_block} WHERE cid = %d", $context->cid);
|
||||
while ($block = db_fetch_object($block_result)) {
|
||||
if (!isset($context->block)) {
|
||||
$context->block = array();
|
||||
}
|
||||
$block->bid = $block->module ."_". $block->delta;
|
||||
$context->block[$block->bid] = $block;
|
||||
}
|
||||
// Clear out identifier
|
||||
unset($context->cid);
|
||||
context_save_context($context);
|
||||
}
|
||||
}
|
||||
|
||||
module_enable(array('context_contrib'));
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update script for API change in path condition.
|
||||
*/
|
||||
function context_update_6002() {
|
||||
define('CONTEXT_STORAGE_DEFAULT', 0);
|
||||
define('CONTEXT_STORAGE_OVERRIDDEN', 1);
|
||||
define('CONTEXT_STORAGE_NORMAL', 2);
|
||||
|
||||
// Iterate through all DB-stored contexts and incorporate path
|
||||
// wildcards into their path conditions. Any exported/default
|
||||
// contexts will need to be updated by hand.
|
||||
$contexts = context_enabled_contexts();
|
||||
foreach ($contexts as $context) {
|
||||
if (($context->type == CONTEXT_STORAGE_NORMAL || $context->type == CONTEXT_STORAGE_OVERRIDDEN) && (!empty($context->path) && is_array($context->path))) {
|
||||
$changed = FALSE;
|
||||
foreach ($context->path as $k => $v) {
|
||||
if ($v != '<front>' && strpos($v, '*') === FALSE) {
|
||||
$changed = TRUE;
|
||||
$context->path[$k] = "{$v}*";
|
||||
}
|
||||
}
|
||||
if ($changed) {
|
||||
context_save_context($context);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove deprecated tables from context_ui.
|
||||
*/
|
||||
function context_update_6003() {
|
||||
$ret = array();
|
||||
$tables = array('context_ui', 'context_ui_setter', 'context_ui_getter', 'context_ui_block');
|
||||
foreach ($tables as $table) {
|
||||
if (db_table_exists($table)) {
|
||||
db_drop_table($ret, $table);
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update 6301: Update schema.
|
||||
*/
|
||||
function context_update_6301() {
|
||||
// Install CTools.
|
||||
drupal_install_modules(array('ctools'));
|
||||
|
||||
$schema = array(
|
||||
'fields' => array(
|
||||
'name' => array(
|
||||
'description' => 'The primary identifier for a context.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'description' => array(
|
||||
'description' => 'Description for this context.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'tag' => array(
|
||||
'description' => 'Tag for this context.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'conditions' => array(
|
||||
'description' => 'Serialized storage of all context condition settings.',
|
||||
'type' => 'text',
|
||||
'serialize' => TRUE,
|
||||
),
|
||||
'reactions' => array(
|
||||
'description' => 'Serialized storage of all context reaction settings.',
|
||||
'type' => 'text',
|
||||
'serialize' => TRUE,
|
||||
),
|
||||
),
|
||||
'primary key' => array('name'),
|
||||
);
|
||||
$ret = array();
|
||||
if (db_table_exists('context')) {
|
||||
$result = db_query("SELECT * FROM {context}");
|
||||
|
||||
// Migrate old contexts into new table.
|
||||
$contexts = array();
|
||||
while ($context = db_fetch_object($result)) {
|
||||
$data = unserialize($context->data);
|
||||
unset($context->data);
|
||||
foreach ($data as $k => $v) {
|
||||
$context->{$k} = $v;
|
||||
}
|
||||
$contexts["{$context->namespace}-{$context->attribute}-{$context->value}"] = $context;
|
||||
}
|
||||
|
||||
// Drop the existing context table and create one using the new schema.
|
||||
db_drop_table($ret, 'context');
|
||||
db_create_table($ret, 'context', $schema);
|
||||
|
||||
// Migrate objects.
|
||||
context_migrate_api_3($ret, $contexts);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update 6302: Update old context exportables. This update script may be
|
||||
* re-run at any time to update context 2 objects that have been exported.
|
||||
*/
|
||||
function context_update_6302() {
|
||||
$contexts = array();
|
||||
// Invoke context 2 default hooks so that the contexts can be migrated.
|
||||
foreach (module_invoke_all('context_default_contexts') as $context) {
|
||||
$context = (object) $context;
|
||||
if (!isset($context->api_version)) {
|
||||
$contexts["{$context->namespace}-{$context->attribute}-{$context->value}"] = $context;
|
||||
}
|
||||
}
|
||||
// Migrate objects.
|
||||
$ret = array();
|
||||
context_migrate_api_3($ret, $contexts);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update 6303: Add field for context condition mode.
|
||||
*/
|
||||
function context_update_6303() {
|
||||
$ret = array();
|
||||
$spec = array(
|
||||
'description' => 'Condition mode for this context.',
|
||||
'type' => 'int',
|
||||
'default' => 0,
|
||||
);
|
||||
db_add_field($ret, 'context', 'condition_mode', $spec);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update 6304: Rename variable 'context_ui_show_empty_regions'.
|
||||
*/
|
||||
function context_update_6304() {
|
||||
if (!db_result(db_query("SELECT name FROM {variable} WHERE name = 'context_reaction_block_all_regions'"))) {
|
||||
db_query("UPDATE {variable} SET name = 'context_reaction_block_all_regions' WHERE name = 'context_ui_show_empty_regions'");
|
||||
return array(array('success' => TRUE, 'query' => 'Variable renamed successfully.'));
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to update context 2 objects to context 3.
|
||||
*/
|
||||
function context_migrate_api_3(&$ret, $contexts) {
|
||||
foreach ($contexts as $context) {
|
||||
if (!db_result(db_query("SELECT name FROM {context} WHERE name = '%s'", "{$context->namespace}-{$context->attribute}-{$context->value}"))) {
|
||||
$new = array(
|
||||
'name' => "{$context->namespace}-{$context->attribute}-{$context->value}",
|
||||
'description' => isset($context->description) ? $context->description : '',
|
||||
'tag' => '',
|
||||
'conditions' => array(),
|
||||
'reactions' => array(),
|
||||
);
|
||||
// Migration condition/reaction settings.
|
||||
// Some have been renamed. Map them.
|
||||
$conditions = array(
|
||||
'node' => 'node',
|
||||
'user' => 'user',
|
||||
'book' => 'book',
|
||||
'sitewide' => 'sitewide',
|
||||
'path' => 'path',
|
||||
'menu_trail' => 'menu',
|
||||
'views' => 'views',
|
||||
'nodequeue' => 'nodequeue'
|
||||
);
|
||||
foreach ($conditions as $old_key => $new_key) {
|
||||
if (isset($context->{$old_key})) {
|
||||
$values = $context->{$old_key};
|
||||
$new['conditions'][$new_key] = array(
|
||||
'values' => is_array($values) ? $values : array($values),
|
||||
'options' => array()
|
||||
);
|
||||
}
|
||||
}
|
||||
$reactions = array(
|
||||
'menu' => 'menu',
|
||||
'theme_section' => 'theme',
|
||||
'css_injector' => 'css_injector',
|
||||
'block' => 'block',
|
||||
);
|
||||
foreach ($reactions as $old_key => $new_key) {
|
||||
if (isset($context->{$old_key})) {
|
||||
// Special treatment for blocks.
|
||||
if ($old_key === 'block') {
|
||||
foreach ($context->block as $block) {
|
||||
$block = (array)$block;
|
||||
$new['reactions']['block']['blocks'][$block['module'] .'-'. $block['delta']] = $block;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$new['reactions'][$new_key] = $context->{$old_key};
|
||||
}
|
||||
}
|
||||
}
|
||||
$new['conditions'] = serialize($new['conditions']);
|
||||
$new['reactions'] = serialize($new['reactions']);
|
||||
|
||||
// Update_sql does not escape strings properly.
|
||||
db_query("INSERT INTO {context} (name,description,tag,conditions,reactions) VALUES ('%s', '%s', '%s', '%s', '%s')", $new['name'], $new['description'], $new['tag'], $new['conditions'], $new['reactions']);
|
||||
|
||||
// Notify the user of any keys that were not migrated.
|
||||
$known_keys = array_merge(array_keys($conditions), array_keys($reactions), array('cid', 'system', 'namespace', 'attribute', 'value', 'description'));
|
||||
$unmigrated = array_diff(array_keys((array) $context), $known_keys);
|
||||
if (!empty($unmigrated)) {
|
||||
$unmigrated = implode(', ', $unmigrated);
|
||||
$ret[] = array(
|
||||
'success' => TRUE,
|
||||
'query' => "Updated context: {$new['name']}. The following properties could not be migrated: {$unmigrated}."
|
||||
);
|
||||
}
|
||||
else {
|
||||
$ret[] = array(
|
||||
'success' => TRUE,
|
||||
'query' => "Updated context: {$new['name']}."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,525 @@
|
|||
<?php
|
||||
|
||||
require('context.core.inc');
|
||||
|
||||
define('CONTEXT_GET', 0);
|
||||
define('CONTEXT_SET', 1);
|
||||
define('CONTEXT_ISSET', 2);
|
||||
define('CONTEXT_CLEAR', 3);
|
||||
|
||||
define('CONTEXT_CONDITION_MODE_OR', 0);
|
||||
define('CONTEXT_CONDITION_MODE_AND', 1);
|
||||
|
||||
/**
|
||||
* Master context function. Avoid calling this directly -- use one of the helper functions below.
|
||||
*
|
||||
* @param $op
|
||||
* The operation to perform - handled by the context helper functions. Use them.
|
||||
* @param $namespace
|
||||
* A string to be used as the namespace for the context information.
|
||||
* @param $attribute
|
||||
* Usually a string to be used as a key to set/retrieve context information. An array can
|
||||
* also be used when setting context to establish an entire context namespace at once.
|
||||
* (At some point objects may also be accepted, but currently functionaliy isn't complete.)
|
||||
* @param $value
|
||||
* A value to set for the provided key. If omitted the value will be set to true.
|
||||
*
|
||||
* @return
|
||||
* Either the requested value, or false if the operation fails.
|
||||
*/
|
||||
function context_context($op = CONTEXT_GET, $namespace = NULL, $attribute = NULL, $value = NULL) {
|
||||
static $context;
|
||||
$context = !$context ? array() : $context;
|
||||
switch ($op) {
|
||||
case CONTEXT_GET:
|
||||
// return entire context
|
||||
if (!$namespace) {
|
||||
return $context;
|
||||
}
|
||||
// return entire space if set
|
||||
else if (isset($context[(string) $namespace])) {
|
||||
// return val of key from space
|
||||
if (is_array($context[(string) $namespace]) && isset($context[(string) $namespace][(string) $attribute])) {
|
||||
return $context[(string) $namespace][(string) $attribute];
|
||||
}
|
||||
elseif (!$attribute) {
|
||||
return $context[(string) $namespace];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CONTEXT_SET:
|
||||
// bail if invalid space is specified or context is already set
|
||||
if (is_string($namespace) || is_int($namespace)) {
|
||||
// initialize namespace if no key is specified
|
||||
if (!$attribute) {
|
||||
$context[(string) $namespace] = array();
|
||||
return TRUE;
|
||||
}
|
||||
// set to true if key is a usable identifier. otherwise, allow a key or object to be inserted
|
||||
if ($value === NULL) {
|
||||
if (is_string($attribute) || is_int($attribute)) {
|
||||
$context[(string) $namespace][(string) $attribute] = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
elseif (is_array($attribute) || is_object($attribute)) {
|
||||
$context[(string) $namespace] = $attribute;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
// set value if key is valid
|
||||
if ((is_string($attribute) || is_int($attribute)) && $value !== NULL) {
|
||||
$context[$namespace][$attribute] = $value;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CONTEXT_ISSET:
|
||||
// return entire context
|
||||
if (!$namespace) return FALSE;
|
||||
if (!$attribute) {
|
||||
// return entire space if set
|
||||
return isset($context[$namespace]);
|
||||
}
|
||||
// return val of key from space
|
||||
return isset($context[$namespace][$attribute]);
|
||||
case CONTEXT_CLEAR:
|
||||
$context = array();
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a context by namespace + attribute.
|
||||
*/
|
||||
function context_set($namespace, $attribute = NULL, $value = NULL) {
|
||||
return context_context(CONTEXT_SET, $namespace, $attribute, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a context by namespace + (optional) attribute.
|
||||
*/
|
||||
function context_get($namespace = NULL, $attribute = NULL) {
|
||||
return context_context(CONTEXT_GET, $namespace, $attribute, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean for whether a context namespace + attribute have been set.
|
||||
*/
|
||||
function context_isset($namespace = NULL, $attribute = NULL) {
|
||||
return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated context_exists() function. Retained for backwards
|
||||
* compatibility -- please use context_isset() instead.
|
||||
*/
|
||||
function context_exists($namespace = NULL, $attribute = NULL) {
|
||||
return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears static context array() -- meant only for testing
|
||||
*/
|
||||
function context_clear() {
|
||||
return context_context(CONTEXT_CLEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented hooks ==================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_ctools_plugin_plugins().
|
||||
*/
|
||||
function context_ctools_plugin_plugins() {
|
||||
return array(
|
||||
'cache' => TRUE,
|
||||
'use hooks' => TRUE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_context_plugins().
|
||||
*
|
||||
* This is a ctools plugins hook.
|
||||
*/
|
||||
function context_context_plugins() {
|
||||
module_load_include('inc', 'context', 'context.plugins');
|
||||
return _context_context_plugins();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of hook_context_registry().
|
||||
*/
|
||||
function context_context_registry() {
|
||||
module_load_include('inc', 'context', 'context.plugins');
|
||||
return _context_context_registry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_init().
|
||||
*/
|
||||
function context_init() {
|
||||
if ($plugin = context_get_plugin('condition', 'path')) {
|
||||
$plugin->execute();
|
||||
}
|
||||
if ($plugin = context_get_plugin('condition', 'language')) {
|
||||
global $language;
|
||||
$plugin->execute($language->language);
|
||||
}
|
||||
if ($plugin = context_get_plugin('condition', 'user')) {
|
||||
global $user;
|
||||
$plugin->execute($user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load & crud functions ==============================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context loader.
|
||||
*
|
||||
* @param $name
|
||||
* The name for this context object.
|
||||
*
|
||||
* @return
|
||||
* Returns a fully-loaded context definition.
|
||||
*/
|
||||
function context_load($name = NULL, $reset = FALSE) {
|
||||
ctools_include('export');
|
||||
static $contexts;
|
||||
static $altered;
|
||||
if (!isset($contexts) || $reset) {
|
||||
$contexts = $altered = array();
|
||||
if (!$reset && $contexts = context_cache_get('context')) {
|
||||
// Nothing here.
|
||||
}
|
||||
else {
|
||||
if ($reset) {
|
||||
ctools_export_load_object_reset('context');
|
||||
}
|
||||
$contexts = ctools_export_load_object('context', 'all');
|
||||
context_cache_set('context', $contexts);
|
||||
}
|
||||
}
|
||||
if (isset($name)) {
|
||||
// Allow other modules to alter the value just before it's returned.
|
||||
if (isset($contexts[$name]) && !isset($altered[$name])) {
|
||||
$altered[$name] = TRUE;
|
||||
drupal_alter('context_load', $contexts[$name]);
|
||||
}
|
||||
return isset($contexts[$name]) ? $contexts[$name] : FALSE;
|
||||
}
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts or updates a context object into the database.
|
||||
* @TODO: should probably return the new cid on success -- make sure
|
||||
* this doesn't break any checks elsewhere.
|
||||
*
|
||||
* @param $context
|
||||
* The context object to be inserted.
|
||||
*
|
||||
* @return
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
function context_save($context) {
|
||||
$existing = context_load($context->name, TRUE);
|
||||
if ($existing && ($existing->export_type & EXPORT_IN_DATABASE)) {
|
||||
drupal_write_record('context', $context, 'name');
|
||||
}
|
||||
else {
|
||||
drupal_write_record('context', $context);
|
||||
}
|
||||
context_load(NULL, TRUE);
|
||||
context_invalidate_cache();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing context.
|
||||
*
|
||||
* @param $context
|
||||
* The context object to be deleted.
|
||||
*
|
||||
* @return
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
function context_delete($context) {
|
||||
if (isset($context->name) && ($context->export_type & EXPORT_IN_DATABASE)) {
|
||||
db_query("DELETE FROM {context} WHERE name = '%s'", $context->name);
|
||||
context_invalidate_cache();
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the specified context.
|
||||
*/
|
||||
function context_export($context, $indent = '') {
|
||||
$output = ctools_export_object('context', $context, $indent);
|
||||
$translatables = array();
|
||||
foreach (array('description', 'tag') as $key) {
|
||||
if (!empty($context->{$key})) {
|
||||
$translatables[] = $context->{$key};
|
||||
}
|
||||
}
|
||||
$translatables = array_filter(array_unique($translatables));
|
||||
if (!empty($translatables)) {
|
||||
$output .= "\n";
|
||||
$output .= "{$indent}// Translatables\n";
|
||||
$output .= "{$indent}// Included for use with string extractors like potx.\n";
|
||||
sort($translatables);
|
||||
foreach ($translatables as $string) {
|
||||
$output .= "{$indent}t(" . ctools_var_export($string) . ");\n";
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* API FUNCTIONS ======================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* CTools list callback for bulk export.
|
||||
*/
|
||||
function context_context_list() {
|
||||
$contexts = context_load(NULL, TRUE);
|
||||
$list = array();
|
||||
foreach ($contexts as $context) {
|
||||
$list[$context->name] = $context->name;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around cache_get() to make it easier for context to pull different
|
||||
* datastores from a single cache row.
|
||||
*/
|
||||
function context_cache_get($key, $reset = FALSE) {
|
||||
static $cache;
|
||||
if (!isset($cache) || $reset) {
|
||||
$cache = cache_get('context', 'cache');
|
||||
$cache = $cache ? $cache->data : array();
|
||||
}
|
||||
return !empty($cache[$key]) ? $cache[$key] : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around cache_set() to make it easier for context to write different
|
||||
* datastores to a single cache row.
|
||||
*/
|
||||
function context_cache_set($key, $value) {
|
||||
$cache = cache_get('context', 'cache');
|
||||
$cache = $cache ? $cache->data : array();
|
||||
$cache[$key] = $value;
|
||||
cache_set('context', $cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around context_load() that only returns enabled contexts.
|
||||
*/
|
||||
function context_enabled_contexts($reset = FALSE) {
|
||||
$enabled = array();
|
||||
foreach (context_load(NULL, $reset) as $context) {
|
||||
if (empty($context->disabled)) {
|
||||
$enabled[$context->name] = $context;
|
||||
}
|
||||
}
|
||||
return $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue or activate contexts that have met the specified condition.
|
||||
*
|
||||
* @param $context
|
||||
* The context object to queue or activate.
|
||||
* @param $condition
|
||||
* String. Name for the condition that has been met.
|
||||
* @param $reset
|
||||
* Reset flag for the queue static cache.
|
||||
*/
|
||||
function context_condition_met($context, $condition, $reset = FALSE) {
|
||||
static $queue;
|
||||
if (!isset($queue) || $reset) {
|
||||
$queue = array();
|
||||
}
|
||||
if (!context_isset('context', $context->name)) {
|
||||
// Context is using AND mode. Queue it.
|
||||
if (isset($context->condition_mode) && $context->condition_mode == CONTEXT_CONDITION_MODE_AND) {
|
||||
$queue[$context->name][$condition] = $condition;
|
||||
|
||||
// If all conditions have been met. set the context.
|
||||
if (!array_diff(array_keys($context->conditions), $queue[$context->name])) {
|
||||
context_set('context', $context->name, $context);
|
||||
}
|
||||
}
|
||||
// Context is using OR mode. Set it.
|
||||
else {
|
||||
context_set('context', $context->name, $context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads any active contexts with associated reactions. This should be run
|
||||
* at a late stage of the page load to ensure that relevant contexts have been set.
|
||||
*/
|
||||
function context_active_contexts() {
|
||||
$contexts = context_get('context');
|
||||
return !empty($contexts) && is_array($contexts) ? $contexts : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an associative array of conditions => context identifiers to allow
|
||||
* contexts to be set by different conditions.
|
||||
*/
|
||||
function context_condition_map($reset = FALSE) {
|
||||
static $condition_map;
|
||||
if (!isset($condition_map) || $reset) {
|
||||
if (!$reset && $cache = context_cache_get('condition_map')) {
|
||||
$condition_map = $cache;
|
||||
}
|
||||
else {
|
||||
$condition_map = array();
|
||||
foreach (array_keys(context_conditions()) as $condition) {
|
||||
if ($plugin = context_get_plugin('condition', $condition)) {
|
||||
foreach (context_enabled_contexts() as $context) {
|
||||
$values = $plugin->fetch_from_context($context, 'values');
|
||||
foreach ($values as $value) {
|
||||
if (!isset($condition_map[$condition][$value])) {
|
||||
$condition_map[$condition][$value] = array();
|
||||
}
|
||||
$condition_map[$condition][$value][] = $context->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
context_cache_set('condition_map', $condition_map);
|
||||
}
|
||||
}
|
||||
return $condition_map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all context caches().
|
||||
* @TODO: Update to use a CTools API function for clearing plugin caches
|
||||
* when/if it becomes available.
|
||||
*/
|
||||
function context_invalidate_cache() {
|
||||
cache_clear_all('context', 'cache', TRUE);
|
||||
cache_clear_all('plugins:context', 'cache', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_flush_caches().
|
||||
*/
|
||||
function context_flush_caches() {
|
||||
context_invalidate_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive helper function to determine whether an array and its
|
||||
* children are entirely empty.
|
||||
*/
|
||||
function context_empty($element) {
|
||||
$empty = TRUE;
|
||||
if (is_array($element)) {
|
||||
foreach ($element as $child) {
|
||||
$empty = $empty && context_empty($child);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$empty = $empty && empty($element);
|
||||
}
|
||||
return $empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a plugin handler.
|
||||
*/
|
||||
function context_get_plugin($type = 'condition', $key, $reset = FALSE) {
|
||||
static $cache = array();
|
||||
if (!isset($cache[$type][$key]) || $reset) {
|
||||
switch ($type) {
|
||||
case 'condition':
|
||||
$registry = context_conditions();
|
||||
break;
|
||||
case 'reaction':
|
||||
$registry = context_reactions();
|
||||
break;
|
||||
}
|
||||
if (isset($registry[$key], $registry[$key]['plugin'])) {
|
||||
ctools_include('plugins');
|
||||
$info = $registry[$key];
|
||||
$plugins = ctools_get_plugins('context', 'plugins');
|
||||
if (isset($plugins[$info['plugin']]) && $class = ctools_plugin_get_class($plugins[$info['plugin']], 'handler')) {
|
||||
$cache[$type][$key] = new $class($key, $info);
|
||||
}
|
||||
}
|
||||
}
|
||||
return isset($cache[$type][$key]) ? $cache[$type][$key] : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get info for modules.
|
||||
* @TODO: It really hurts that we have to do this. See a similar function in
|
||||
* features.module and recognize that this should be in system.module but is not...
|
||||
*/
|
||||
function context_get_info($type = NULL, $name = NULL, $reset = FALSE) {
|
||||
static $info;
|
||||
if (!isset($info) || $reset) {
|
||||
$result = db_query("SELECT name,type,info FROM {system}");
|
||||
while ($row = db_fetch_object($result)) {
|
||||
$info[$row->type][$row->name] = unserialize($row->info);
|
||||
}
|
||||
}
|
||||
if (isset($type, $name)) {
|
||||
return isset($info[$type][$name]) ? $info[$type][$name] : FALSE;
|
||||
}
|
||||
else if (isset($type)) {
|
||||
return isset($info[$type]) ? $info[$type] : FALSE;
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all context conditions.
|
||||
*/
|
||||
function context_conditions($reset = FALSE) {
|
||||
return _context_registry('conditions', $reset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all context reactions.
|
||||
*/
|
||||
function context_reactions($reset = FALSE) {
|
||||
return _context_registry('reactions', $reset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves & caches the context registry.
|
||||
*/
|
||||
function _context_registry($key = NULL, $reset = FALSE) {
|
||||
static $registry;
|
||||
if (!isset($registry) || $reset) {
|
||||
if (!$reset && $cache = context_cache_get('registry')) {
|
||||
$registry = $cache;
|
||||
}
|
||||
else {
|
||||
$registry = module_invoke_all('context_registry');
|
||||
drupal_alter('context_registry', $registry);
|
||||
context_cache_set('registry', $registry);
|
||||
}
|
||||
}
|
||||
if (isset($key)) {
|
||||
return isset($registry[$key]) ? $registry[$key] : array();
|
||||
}
|
||||
return $registry;
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Context registry.
|
||||
*/
|
||||
function _context_context_registry() {
|
||||
$registry = array();
|
||||
$registry['conditions'] = array(
|
||||
'context' => array(
|
||||
'title' => t('Context'),
|
||||
'description' => t('Set this context on the basis of other active contexts. Put each context on a separate line. You can use the <code>*</code> character as a wildcard and <code>~</code> to exclude one or more contexts.'),
|
||||
'plugin' => 'context_condition_context',
|
||||
),
|
||||
'node' => array(
|
||||
'title' => t('Node type'),
|
||||
'description' => t('Set this context when viewing a node page or using the add/edit form of one of these content types.'),
|
||||
'plugin' => 'context_condition_node',
|
||||
),
|
||||
'sitewide' => array(
|
||||
'title' => t('Sitewide context'),
|
||||
'description' => t('Should this context always be set? If <strong>true</strong>, this context will be active across your entire site.'),
|
||||
'plugin' => 'context_condition_sitewide',
|
||||
),
|
||||
'path' => array(
|
||||
'title' => t('Path'),
|
||||
'description' => t('Set this context when any of the paths above match the page path. Put each path on a separate line. You can use the "*" character as a wildcard and <code>~</code> to exclude one or more paths. Use <front> for the site front page.'),
|
||||
'plugin' => 'context_condition_path',
|
||||
),
|
||||
'user' => array(
|
||||
'title' => t('User role'),
|
||||
'description' => t('Set this context when the current user has one of the selected role(s).'),
|
||||
'plugin' => 'context_condition_user',
|
||||
),
|
||||
'user_page' => array(
|
||||
'title' => t('User page'),
|
||||
'description' => t('Set this context when viewing a user page.'),
|
||||
'plugin' => 'context_condition_user_page',
|
||||
),
|
||||
);
|
||||
if (module_exists('menu')) {
|
||||
$registry['conditions']['menu'] = array(
|
||||
'title' => t('Menu'),
|
||||
'description' => t('Set this context when any of the selected menu items belong to the current active menu trail.'),
|
||||
'plugin' => 'context_condition_menu',
|
||||
);
|
||||
}
|
||||
if (module_exists('views')) {
|
||||
$registry['conditions']['views'] = array(
|
||||
'title' => t('Views'),
|
||||
'description' => t('Set this context when displaying the page of one of these views.'),
|
||||
'plugin' => 'context_condition_views',
|
||||
);
|
||||
}
|
||||
if (module_exists('book')) {
|
||||
$registry['conditions']['book'] = array(
|
||||
'title' => t('Book'),
|
||||
'description' => t('Set this context when a node in the selected book is viewed.'),
|
||||
'plugin' => 'context_condition_book',
|
||||
);
|
||||
$registry['conditions']['bookroot'] = array(
|
||||
'title' => t('Book root'),
|
||||
'description' => t('Set this context when viewing a node whose root book is of the selected type.'),
|
||||
'plugin' => 'context_condition_bookroot',
|
||||
);
|
||||
}
|
||||
if (module_exists('locale')) {
|
||||
$registry['conditions']['language'] = array(
|
||||
'title' => t('Language'),
|
||||
'description' => t('Set this context when viewing the site in the selected language.'),
|
||||
'plugin' => 'context_condition_language',
|
||||
);
|
||||
}
|
||||
if (module_exists('taxonomy')) {
|
||||
$registry['conditions']['node_taxonomy'] = array(
|
||||
'title' => t('Taxonomy'),
|
||||
'description' => t('Set this context when viewing a node with the selected taxonomy terms.'),
|
||||
'plugin' => 'context_condition_node_taxonomy',
|
||||
);
|
||||
}
|
||||
$registry['reactions'] = array(
|
||||
'block' => array(
|
||||
'title' => t('Blocks'),
|
||||
'description' => t('Control block visibility using context.'),
|
||||
'plugin' => 'context_reaction_block',
|
||||
),
|
||||
'breadcrumb' => array(
|
||||
'title' => t('Breadcrumb'),
|
||||
'description' => t('Set the breadcrumb trail to the selected menu item.'),
|
||||
'plugin' => 'context_reaction_breadcrumb',
|
||||
),
|
||||
'theme' => array(
|
||||
'title' => t('Theme'),
|
||||
'description' => t('Control theme variables using context.'),
|
||||
'plugin' => 'context_reaction_theme',
|
||||
),
|
||||
'debug' => array(
|
||||
'title' => t('Debug'),
|
||||
'description' => t('Debug output reaction for SimpleTest.'),
|
||||
'plugin' => 'context_reaction_debug',
|
||||
),
|
||||
);
|
||||
if (module_exists('menu')) {
|
||||
$registry['reactions']['menu'] = array(
|
||||
'title' => t('Menu'),
|
||||
'description' => t('Control menu active class using context.'),
|
||||
'plugin' => 'context_reaction_menu',
|
||||
);
|
||||
}
|
||||
if (module_exists('css_injector')) {
|
||||
$registry['reactions']['css_injector'] = array(
|
||||
'title' => t('CSS Injector'),
|
||||
'description' => t('Inject the selected css when this context is set.'),
|
||||
'plugin' => 'context_reaction_css_injector',
|
||||
);
|
||||
}
|
||||
return $registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context plugins.
|
||||
*/
|
||||
function _context_context_plugins() {
|
||||
$plugins = array();
|
||||
|
||||
/**
|
||||
* Conditions.
|
||||
*/
|
||||
$plugins['context_condition'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition.inc',
|
||||
'class' => 'context_condition',
|
||||
),
|
||||
);
|
||||
$plugins['context_condition_context'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_context.inc',
|
||||
'class' => 'context_condition_context',
|
||||
'parent' => 'context_condition_path',
|
||||
),
|
||||
);
|
||||
$plugins['context_condition_node'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_node.inc',
|
||||
'class' => 'context_condition_node',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
$plugins['context_condition_sitewide'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_sitewide.inc',
|
||||
'class' => 'context_condition_sitewide',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
$plugins['context_condition_path'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_path.inc',
|
||||
'class' => 'context_condition_path',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
$plugins['context_condition_user'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_user.inc',
|
||||
'class' => 'context_condition_user',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
$plugins['context_condition_user_page'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_user_page.inc',
|
||||
'class' => 'context_condition_user_page',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
$plugins['context_condition_menu'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_menu.inc',
|
||||
'class' => 'context_condition_menu',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
if (module_exists('taxonomy')) {
|
||||
$plugins['context_condition_node_taxonomy'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_node_taxonomy.inc',
|
||||
'class' => 'context_condition_node_taxonomy',
|
||||
'parent' => 'context_condition_node',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (module_exists('locale')) {
|
||||
$plugins['context_condition_language'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_language.inc',
|
||||
'class' => 'context_condition_language',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (module_exists('book')) {
|
||||
$plugins['context_condition_book'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_book.inc',
|
||||
'class' => 'context_condition_book',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
$plugins['context_condition_bookroot'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_bookroot.inc',
|
||||
'class' => 'context_condition_bookroot',
|
||||
'parent' => 'context_condition_node',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (module_exists('views')) {
|
||||
$plugins['context_condition_views'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_condition_views.inc',
|
||||
'class' => 'context_condition_views',
|
||||
'parent' => 'context_condition',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reactions.
|
||||
*/
|
||||
$plugins['context_reaction'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_reaction.inc',
|
||||
'class' => 'context_reaction',
|
||||
),
|
||||
);
|
||||
$plugins['context_reaction_block'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_reaction_block.inc',
|
||||
'class' => 'context_reaction_block',
|
||||
'parent' => 'context_reaction',
|
||||
),
|
||||
);
|
||||
$plugins['context_reaction_breadcrumb'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_reaction_breadcrumb.inc',
|
||||
'class' => 'context_reaction_breadcrumb',
|
||||
'parent' => 'context_reaction_menu',
|
||||
),
|
||||
);
|
||||
$plugins['context_reaction_menu'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_reaction_menu.inc',
|
||||
'class' => 'context_reaction_menu',
|
||||
'parent' => 'context_reaction',
|
||||
),
|
||||
);
|
||||
$plugins['context_reaction_theme'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_reaction_theme.inc',
|
||||
'class' => 'context_reaction_theme',
|
||||
'parent' => 'context_reaction',
|
||||
),
|
||||
);
|
||||
$plugins['context_reaction_debug'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_reaction_debug.inc',
|
||||
'class' => 'context_reaction_debug',
|
||||
'parent' => 'context_reaction',
|
||||
),
|
||||
);
|
||||
if (module_exists('css_injector')) {
|
||||
$plugins['context_reaction_css_injector'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context') .'/plugins',
|
||||
'file' => 'context_reaction_css_injector.inc',
|
||||
'class' => 'context_reaction_css_injector',
|
||||
'parent' => 'context_reaction',
|
||||
),
|
||||
);
|
||||
}
|
||||
return $plugins;
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
Context layouts
|
||||
---------------
|
||||
Context layouts provides a formalized way for themes to declare and switch
|
||||
between page templates using Context. It is a continuation of an old Drupal
|
||||
themer's trick to switch to something besides the standard `page.tpl.php` file
|
||||
for a variety of special-case pages like the site frontpage, login page, admin
|
||||
section, etc.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
In order to use context layouts, your site must meet a few conditions:
|
||||
|
||||
- Context and Context layouts modules are enabled (`admin/build/modules`).
|
||||
- You are using a theme which provides and has declared multiple layouts. (See
|
||||
"Example themes" for themes you can try.)
|
||||
|
||||
|
||||
Basic usage
|
||||
-----------
|
||||
Once you have layouts enabled, you can have a context trigger the usage of a
|
||||
particular layout in either the admin interface (`admin/build/context`) or
|
||||
inline context editor. Different layouts may have fewer or greater regions than
|
||||
the default page template, so adjust your blocks accordingly.
|
||||
|
||||
|
||||
Supporting context layouts in your theme
|
||||
----------------------------------------
|
||||
You can add layouts support to your theme by declaring additional layouts in
|
||||
your theme's info file. Here is an example:
|
||||
|
||||
`example.info`
|
||||
|
||||
name = "Example"
|
||||
description = "Example theme"
|
||||
core = "6.x"
|
||||
engine = "phptemplate"
|
||||
|
||||
regions[left] = "Left sidebar"
|
||||
regions[right] = "Right sidebar"
|
||||
regions[content] = "Content"
|
||||
regions[footer] = "Footer"
|
||||
|
||||
; Layout: Default
|
||||
layouts[default][name] = "Default"
|
||||
layouts[default][description] = "Simple two column page."
|
||||
layouts[default][template] = "page"
|
||||
layouts[default][regions][] = "content"
|
||||
layouts[default][regions][] = "right"
|
||||
|
||||
; Layout: Columns
|
||||
layouts[columns][name] = "3 columns"
|
||||
layouts[columns][description] = "Three column page."
|
||||
layouts[columns][stylesheet] = "layout-columns.css"
|
||||
layouts[columns][template] = "layout-columns"
|
||||
layouts[columns][regions][] = "left"
|
||||
layouts[columns][regions][] = "content"
|
||||
layouts[columns][regions][] = "right"
|
||||
layouts[columns][regions][] = "footer"
|
||||
|
||||
Each layout is declared under `layouts` with the key as the identifier that will
|
||||
be used by context for this layout. You may use any reasonable machine name for
|
||||
each layout, but note that `default` is special -- it will be the default layout
|
||||
for your theme if no other layout is specified.
|
||||
|
||||
The following keys can be declared for each layout:
|
||||
|
||||
- `name`: The human readable name for this layout, shown in the admin UI.
|
||||
- `description`: A short description of your layout, same as above.
|
||||
- `stylesheet`: A stylesheet to be included with the layout. Optional.
|
||||
- `template`: The name of the template file for this layout, without the
|
||||
`.tpl.php` extension.
|
||||
- `region`: An array of regions supported by this layout. Note that any of the
|
||||
regions listed here **must also be declared** in the standard theme `regions`
|
||||
array.
|
||||
|
||||
|
||||
Example themes
|
||||
--------------
|
||||
- Cube, a subtheme included with [Rubik][1] provides a variety of layouts.
|
||||
- [Ginkgo][2] the default theme included with Open Atrium.
|
||||
|
||||
[1]: http://github.com/developmentseed/rubik/downloads
|
||||
[2]: http://github.com/developmentseed/ginkgo/downloads
|
|
@ -0,0 +1,12 @@
|
|||
name = "Context layouts"
|
||||
description = "Allow theme layer to provide multiple region layouts and integrate with context."
|
||||
dependencies[] = "context"
|
||||
package = "Context"
|
||||
core = "6.x"
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-10-17
|
||||
version = "6.x-3.3-boinc-1-dev"
|
||||
core = "6.x"
|
||||
project = "context"
|
||||
datestamp = "1551298073"
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implementation of hook_help().
|
||||
*/
|
||||
function context_layouts_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#context_layouts':
|
||||
$output = file_get_contents(drupal_get_path('module', 'context_layouts') .'/README.txt');
|
||||
return module_exists('markdown') ? filter_xss_admin(module_invoke('markdown', 'filter', 'process', 0, -1, $output)) : '<pre>'. check_plain($output) .'</pre>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_context_plugins().
|
||||
* This is a ctools plugins hook.
|
||||
*/
|
||||
function context_layouts_context_plugins() {
|
||||
return array(
|
||||
'context_layouts_reaction_block' => array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'context_layouts') .'/plugins',
|
||||
'file' => 'context_layouts_reaction_block.inc',
|
||||
'class' => 'context_layouts_reaction_block',
|
||||
'parent' => 'context_reaction_block',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_context_registry_alter().
|
||||
*/
|
||||
function context_layouts_context_registry_alter(&$registry) {
|
||||
if (isset($registry['reactions']['block'])) {
|
||||
$registry['reactions']['block']['plugin'] = 'context_layouts_reaction_block';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_context_page_reaction().
|
||||
*/
|
||||
function context_layouts_context_page_reaction() {
|
||||
$plugin = context_get_plugin('reaction', 'block');
|
||||
if ($plugin && method_exists($plugin, 'add_layout_stylesheet')) {
|
||||
$plugin->add_layout_stylesheet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('page').
|
||||
*/
|
||||
function context_layouts_preprocess_page(&$vars) {
|
||||
$plugin = context_get_plugin('reaction', 'block');
|
||||
if ($plugin && method_exists($plugin, 'add_layout_template')) {
|
||||
$plugin->add_layout_template($vars);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve layouts for the specified theme.
|
||||
*/
|
||||
function context_layouts_get_layouts($theme = NULL, $reset = FALSE) {
|
||||
static $layouts = array();
|
||||
$layouts = $reset ? array() : $layouts;
|
||||
|
||||
global $theme_key;
|
||||
$theme = isset($theme) ? $theme : $theme_key;
|
||||
|
||||
if (!isset($layouts[$theme])) {
|
||||
$info = context_get_info('theme', $theme);
|
||||
$themes = array();
|
||||
|
||||
// Find all our ancestor themes that use layouts.
|
||||
if (isset($info['base theme'])) {
|
||||
while (!empty($info['base theme'])) {
|
||||
$base_theme = $info['base theme'];
|
||||
$info = context_get_info('theme', $base_theme);
|
||||
$themes[$base_theme] = $info;
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble in inheritance order and add the theme on.
|
||||
$themes = array_reverse($themes);
|
||||
$themes[$theme] = context_get_info('theme', $theme);
|
||||
|
||||
// Merge layout info into a single array.
|
||||
foreach ($themes as $key => $info) {
|
||||
if (!empty($info['layouts'])) {
|
||||
foreach ($info['layouts'] as $layout => $layout_info) {
|
||||
$layout_info['theme'] = $key;
|
||||
$layouts[$theme][$layout] = $layout_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isset($layouts[$theme]) ? $layouts[$theme] : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active layout for the current page.
|
||||
*/
|
||||
function context_layouts_get_active_layout($info = TRUE) {
|
||||
$plugin = context_get_plugin('reaction', 'block');
|
||||
if ($plugin && method_exists($plugin, 'get_active_layout')) {
|
||||
return $plugin->get_active_layout($info);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#admin-toolbar div.context-editor-block-layouts {
|
||||
padding:0px 0px 9px;
|
||||
border-bottom:1px solid #333;
|
||||
margin:0px 0px 10px;
|
||||
}
|
||||
|
||||
#admin-toolbar div.context-editor-block-layouts div.form-item { display:inline; }
|
||||
#admin-toolbar div.context-editor-block-layouts select { width:50%; }
|
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
|
||||
class context_layouts_reaction_block extends context_reaction_block {
|
||||
/**
|
||||
* Override of is_enabled_region().
|
||||
* Check that there is an active layout and it supports the given region.
|
||||
*/
|
||||
protected function is_enabled_region($region) {
|
||||
$layout = $this->get_active_layout();
|
||||
if ($layout && isset($layout['regions']) && is_array($layout['regions'])) {
|
||||
return in_array($region, $layout['regions'], TRUE) && parent::is_enabled_region($region);
|
||||
}
|
||||
return parent::is_enabled_region($region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the first layout specified found by any active contexts.
|
||||
*/
|
||||
function get_active_layout($info = TRUE) {
|
||||
$contexts = $this->get_contexts();
|
||||
$layouts = context_layouts_get_layouts();
|
||||
if (!empty($contexts) && !empty($layouts)) {
|
||||
foreach ($contexts as $context) {
|
||||
$values = $this->fetch_from_context($context);
|
||||
if (isset($values['layout']) && isset($layouts[$values['layout']])) {
|
||||
return $info ? $layouts[$values['layout']] : $values['layout'];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback to default layout if provided.
|
||||
if (isset($layouts['default'])) {
|
||||
return $info ? $layouts['default'] : 'default';
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the layout template to page vars.
|
||||
*/
|
||||
function add_layout_template(&$vars) {
|
||||
if ($layout = $this->get_active_layout()) {
|
||||
if (!empty($layout['template'])) {
|
||||
$vars['template_files'][] = $layout['template'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the layout stylesheet to the CSS.
|
||||
*/
|
||||
function add_layout_stylesheet() {
|
||||
if ($layout = $this->get_active_layout()) {
|
||||
if (!empty($layout['stylesheet'])) {
|
||||
drupal_add_css(drupal_get_path('theme', $layout['theme']) .'/'. $layout['stylesheet']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of editor form.
|
||||
*/
|
||||
function editor_form($context) {
|
||||
drupal_add_css(drupal_get_path('module', 'context_layouts') .'/plugins/context_layouts_reaction_block.css');
|
||||
|
||||
$form = parent::editor_form($context);
|
||||
|
||||
if ($layouts = $this->get_layout_options()) {
|
||||
$options = $this->fetch_from_context($context);
|
||||
$form['layout'] = array(
|
||||
// #tree *must* be true for our values to be nested correctly.
|
||||
'#tree' => TRUE,
|
||||
'#prefix' => '<div class="context-editor-block-layouts">',
|
||||
'#suffix' => '</div>',
|
||||
'#weight' => -100,
|
||||
'layout' => array(
|
||||
'#title' => t('Layout'),
|
||||
'#options' => $layouts,
|
||||
'#type' => 'select',
|
||||
'#weight' => -100,
|
||||
'#default_value' => isset($options['layout']) ? $options['layout'] : NULL,
|
||||
),
|
||||
'update' => array(
|
||||
'#value' => t('Change layout'),
|
||||
'#type' => 'submit',
|
||||
),
|
||||
);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of editor form submit.
|
||||
*/
|
||||
function editor_form_submit(&$context, $values) {
|
||||
// Someone has changed the layout, assume that the block values are not actually usable here.
|
||||
if (isset($context->reactions['block']['layout']) && $context->reactions['block']['layout'] != $values['layout']['layout']) {
|
||||
$options = $context->reactions['block'];
|
||||
}
|
||||
else {
|
||||
$options = parent::editor_form_submit($context, $values);
|
||||
}
|
||||
|
||||
if (!empty($values['layout']['layout'])) {
|
||||
$options['layout'] = $values['layout']['layout'];
|
||||
}
|
||||
else {
|
||||
unset($options['layout']);
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of options form.
|
||||
*/
|
||||
function options_form($context) {
|
||||
$form = parent::options_form($context);
|
||||
$options = $this->fetch_from_context($context);
|
||||
|
||||
// Only alter the options form if the theme provides layouts.
|
||||
$theme_key = variable_get('theme_default', 'garland');
|
||||
$layouts = $this->get_layout_options();
|
||||
if (!empty($layouts)) {
|
||||
$form['layout'] = array(
|
||||
'#title' => t('Layout'),
|
||||
'#description' => t('Choose one of the layouts provided by the default theme.'),
|
||||
'#options' => $layouts,
|
||||
'#type' => 'select',
|
||||
'#weight' => -100,
|
||||
'#default_value' => $options['layout'] ? $options['layout'] : NULL,
|
||||
'#attributes' => array('class' => 'context-blockform-layout'),
|
||||
);
|
||||
|
||||
// Add js.
|
||||
// @TODO: Move this to a theme function or somewhere that will get called even
|
||||
// if the form is using a cached version of itself (e.g. when validate fails).
|
||||
drupal_add_js(drupal_get_path('module', 'context_layouts') .'/plugins/context_layouts_reaction_block.js');
|
||||
drupal_add_js(array('contextLayouts' => array('layouts' => $this->get_layout_regions())), 'setting');
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of submit handler.
|
||||
*/
|
||||
function options_form_submit($values) {
|
||||
$options = parent::options_form_submit($values);
|
||||
|
||||
// Only alter the options form if the theme provides layouts.
|
||||
$theme_key = variable_get('theme_default', 'garland');
|
||||
$layouts = context_layouts_get_layouts($theme_key);
|
||||
|
||||
// Check that this is a valid layout.
|
||||
if (!empty($values['layout']) && isset($layouts[$values['layout']])) {
|
||||
$layout = $values['layout'];
|
||||
$options['layout'] = $layout;
|
||||
|
||||
// Remove blocks that don't belong to regions in this layout.
|
||||
if (isset($layouts[$layout]['regions'])) {
|
||||
foreach ($options['blocks'] as $bid => $block) {
|
||||
if (!in_array($block['region'], $layouts[$layout]['regions'])) {
|
||||
unset($options['blocks'][$bid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get layout options for the given theme.
|
||||
*/
|
||||
protected function get_layout_options($theme_key = NULL) {
|
||||
$theme_key = !isset($theme_key) ? variable_get('theme_default', 'garland') : $theme_key;
|
||||
$layouts = context_layouts_get_layouts($theme_key);
|
||||
$layout_options = array();
|
||||
if (!empty($layouts)) {
|
||||
$layout_options[0] = '<'. t('Site default') .'>';
|
||||
foreach ($layouts as $layout => $info) {
|
||||
$layout_options[$layout] = isset($info['name']) ? $info['name'] : $layout_options;
|
||||
}
|
||||
}
|
||||
return $layout_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a layout to region map for the given theme.
|
||||
*/
|
||||
protected function get_layout_regions($theme_key = NULL) {
|
||||
$theme_key = !isset($theme_key) ? variable_get('theme_default', 'garland') : $theme_key;
|
||||
$layouts = context_layouts_get_layouts($theme_key);
|
||||
if (!empty($layouts)) {
|
||||
$layout_regions = array();
|
||||
foreach ($layouts as $layout => $info) {
|
||||
$layout_regions[$layout] = is_array($info['regions']) ? $info['regions'] : array();
|
||||
}
|
||||
}
|
||||
return $layout_regions;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
Drupal.behaviors.contextLayoutsReactionBlock = function(context) {
|
||||
// ContextBlockForm: Init.
|
||||
$('.context-blockform-layout:not(.contextLayoutsProcessed)').each(function() {
|
||||
$(this).addClass('contextLayoutsProcessed');
|
||||
$(this).change(function() {
|
||||
var layout = $(this).val();
|
||||
if (Drupal.settings.contextLayouts.layouts[layout]) {
|
||||
$('#context-blockform td.blocks table').hide();
|
||||
$('#context-blockform td.blocks div.label').hide();
|
||||
for (var key in Drupal.settings.contextLayouts.layouts[layout]) {
|
||||
var region = Drupal.settings.contextLayouts.layouts[layout][key];
|
||||
$('.context-blockform-regionlabel-'+region).show();
|
||||
$('#context-blockform-region-'+region).show();
|
||||
}
|
||||
if (Drupal.contextBlockForm) {
|
||||
Drupal.contextBlockForm.setState();
|
||||
}
|
||||
}
|
||||
});
|
||||
$(this).change();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
Context UI
|
||||
----------
|
||||
Context UI provides an administrative interface for managing and editing
|
||||
Contexts. It is not necessary for the proper functioning of contexts once they
|
||||
are built and can be turned off on most production sites.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
- Context, Context UI modules enabled (`admin/build/modules`)
|
||||
- [jQuery UI 1.x][1] and [Admin 2.x][2] to use the inline context editor.
|
||||
Optional.
|
||||
|
||||
|
||||
Basic usage
|
||||
-----------
|
||||
As a site administrator you can manage your site's contexts at
|
||||
`admin/build/context`. The main page will show you a list of the contexts on the
|
||||
site and give you some options for managing each context.
|
||||
|
||||
When editing or adding a new context, you will be presented with a form to
|
||||
manage some basic information about the context and then alter its conditions
|
||||
and reactions.
|
||||
|
||||
- `name`: The name of your context. This is the main identifier for your context
|
||||
and cannot be changed after you've created it.
|
||||
- `description`: A description or human-readable name for your context. This is
|
||||
displayed in the inline editor if available instead of the name.
|
||||
- `tag`: A category for organizing contexts in the administrative context
|
||||
listing. Optional.
|
||||
|
||||
**Conditions**
|
||||
|
||||
When certain conditions are true, your context will be made active. You can
|
||||
customize the conditions that trigger the activation of your context.
|
||||
|
||||
- **Condition mode**: you can choose to have your context triggered if **ANY**
|
||||
conditions are met or only active when **ALL** conditions are met.
|
||||
- **Adding/removing conditions**: you can add or remove to the conditions on
|
||||
your context using the conditions dropdown.
|
||||
- **Individual settings**: most conditions provide a simple form for selecting
|
||||
individual settings for that condition. For example, the node type condition
|
||||
allows you to choose which node types activate the context.
|
||||
|
||||
**Reactions**
|
||||
|
||||
Whenever a particular context is active, all of its reactions will be run.
|
||||
Like conditions, reactions can be added or removed and have settings that can
|
||||
be configured.
|
||||
|
||||
|
||||
Using the inline editor
|
||||
-----------------------
|
||||
If you have installed jQuery UI and Admin, you can enable the inline context
|
||||
editor:
|
||||
|
||||
1. As an administrative user go to `admin/settings/admin`.
|
||||
2. Check the 'Context editor' block and save.
|
||||
3. When viewing a page with one or more active contexts, you will see the
|
||||
`Context editor` in the admin toolbar.
|
||||
4. You can use the context editor to adjust the conditions under which each
|
||||
context is active and alter its reactions.
|
||||
|
||||
|
||||
[1]: http://drupal.org/project/jquery_ui
|
||||
[2]: http://drupal.org/project/admin
|
|
@ -0,0 +1,173 @@
|
|||
/**
|
||||
* Editor =============================================================
|
||||
*/
|
||||
div.context-editor div.label { float:left; }
|
||||
div.context-editor div.links { float:right; }
|
||||
|
||||
div.context-editor div.context-editable { display:none; }
|
||||
div.context-editor div.links a.done { display:none; }
|
||||
div.context-editor li.context-editing a.edit { display:none; }
|
||||
div.context-editor li.context-editing a.done { display:block; }
|
||||
|
||||
/* Don't display form submission buttons initially or when editing */
|
||||
body.context-editing div.context-editor div.links { display:none; }
|
||||
body.context-editing div.context-editor li.context-editing div.links { display:block; }
|
||||
|
||||
div.context-editor div.buttons { display:none; }
|
||||
form.edited div.context-editor div.buttons { display:block; }
|
||||
body.context-editing form.edited div.context-editor div.buttons { display:none; }
|
||||
|
||||
/**
|
||||
* Styles for visual integration with admin.
|
||||
*/
|
||||
#admin-toolbar div.context-editor div.links a:hover {
|
||||
background:#eee;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
#admin-toolbar div.context-editor div.links a {
|
||||
float:left;
|
||||
|
||||
padding:0px 10px;
|
||||
margin-right:5px;
|
||||
|
||||
background:#222;
|
||||
font-size:11px;
|
||||
-moz-border-radius:10px;
|
||||
-webkit-border-radius:10px;
|
||||
}
|
||||
|
||||
div.context-editor div.context-editable { padding:5px 0px; }
|
||||
|
||||
#admin-toolbar div.context-editor div.buttons {
|
||||
padding:10px 0px;
|
||||
text-align:center;
|
||||
background:#111;
|
||||
}
|
||||
|
||||
/**
|
||||
* Horizontal
|
||||
*/
|
||||
#admin-toolbar.horizontal form.edited div.context-editor div.buttons,
|
||||
#admin-toolbar.horizontal div.context-editor div.item-list {
|
||||
float:left;
|
||||
clear:left;
|
||||
width:30%;
|
||||
}
|
||||
|
||||
#admin-toolbar.horizontal div.context-editor div.contexts {
|
||||
width:69.9%;
|
||||
float:right;
|
||||
}
|
||||
|
||||
#admin-toolbar.horizontal div.context-editor div.context-editable { padding-left:20px }
|
||||
|
||||
/**
|
||||
* Admin listing page =================================================
|
||||
*/
|
||||
table.context-admin td.tag { font-style:italic; }
|
||||
|
||||
table.context-admin td.ctools-export-ui-name {
|
||||
width:75%;
|
||||
padding-left:20px;
|
||||
}
|
||||
|
||||
table.context-admin td.ctools-export-ui-operations { white-space:nowrap; }
|
||||
|
||||
table.context-admin td.ctools-export-ui-storage { color:#999; }
|
||||
|
||||
table.context-admin div.description {
|
||||
padding-left:10px;
|
||||
margin:0px;
|
||||
}
|
||||
|
||||
table.context-admin input.form-text { width:90%; }
|
||||
|
||||
/**
|
||||
* Context form =======================================================
|
||||
*/
|
||||
.context-plugins {
|
||||
position:relative;
|
||||
margin:0px 0px 10px;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-info {
|
||||
padding:10px 10px 9px;
|
||||
border-bottom:1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-info div.description {
|
||||
margin:0px 0px 10px;
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-selector {
|
||||
width:25%;
|
||||
background:#fff;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-list .disabled { display:none; }
|
||||
|
||||
.context-plugins .context-plugin-list ul {
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-list li {
|
||||
list-style:none;
|
||||
list-style-image:none;
|
||||
background:transparent;
|
||||
|
||||
padding:0px;
|
||||
margin:0px;
|
||||
border:0px;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-list li a {
|
||||
display:block;
|
||||
position:relative;
|
||||
padding:5px 10px 4px;
|
||||
border-bottom:1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-list li a.active-form {
|
||||
background:#f8f8f8;
|
||||
color:#333;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-list li span.remove {
|
||||
display:none;
|
||||
position:absolute;
|
||||
top:5px;
|
||||
right:10px;
|
||||
|
||||
font-size:9px;
|
||||
font-weight:normal;
|
||||
|
||||
-moz-border-radius:5px;
|
||||
-webkit-border-radius:5px;
|
||||
padding:0px 5px;
|
||||
background:#fff;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-list li a:hover span.remove { display:block; }
|
||||
|
||||
.context-plugins .context-plugin-forms {
|
||||
float:right;
|
||||
width:75%;
|
||||
background:#f8f8f8;
|
||||
min-height:200px;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-forms .context-plugin-form {
|
||||
padding:10px;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.context-plugins .context-plugin-forms .active-form { display:block; }
|
||||
|
||||
.context-plugins .context-plugin-form .form-checkboxes {
|
||||
max-height:300px;
|
||||
overflow:auto;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
name = Context UI
|
||||
description = "Provides a simple UI for settings up a site structure using Context."
|
||||
dependencies[] = context
|
||||
package = Context
|
||||
core = "6.x"
|
||||
; Information added by drupal.org packaging script on 2013-10-17
|
||||
version = "6.x-3.3-boinc-1-dev"
|
||||
core = "6.x"
|
||||
project = "context"
|
||||
datestamp = "1551298073"
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Update 6004: Placeholder update to ensure migrations from older versions
|
||||
* in Aegir do not fail.
|
||||
*/
|
||||
function context_ui_update_6004() {
|
||||
return array();
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
|
||||
/**
|
||||
* Context plugin form.
|
||||
*/
|
||||
function DrupalContextPlugins(form) {
|
||||
this.form = form;
|
||||
|
||||
// Sync the form selector and state field with the list of plugins currently enabled.
|
||||
this.setState = function() {
|
||||
var state = [];
|
||||
$('.context-plugin-list > li', this.form).each(function() {
|
||||
var plugin = $(this).attr('class').split('context-plugin-')[1].split(' ')[0];
|
||||
if ($(this).is('.disabled')) {
|
||||
$('.context-plugin-selector select option[value='+plugin+']', this.form).show();
|
||||
}
|
||||
else {
|
||||
state.push(plugin);
|
||||
$('.context-plugin-selector select option[value='+plugin+']', this.form).hide();
|
||||
}
|
||||
});
|
||||
// Set the hidden plugin list state.
|
||||
$('.context-plugin-selector input.context-plugins-state', this.form).val(state.join(','));
|
||||
|
||||
// Reset the selector.
|
||||
$('.context-plugin-selector select', this.form).val(0);
|
||||
return this;
|
||||
};
|
||||
|
||||
// Add a plugin to the list.
|
||||
this.addPlugin = function(plugin) {
|
||||
$('.context-plugin-list > li.context-plugin-'+plugin, this.form).removeClass('disabled');
|
||||
this.showForm(plugin).setState();
|
||||
return this;
|
||||
};
|
||||
|
||||
// Remove a plugin from the list.
|
||||
this.removePlugin = function(plugin) {
|
||||
$('.context-plugin-list > li.context-plugin-'+plugin, this.form).addClass('disabled');
|
||||
this.hideForm(plugin).setState();
|
||||
return this;
|
||||
};
|
||||
|
||||
// Show a plugin form.
|
||||
this.showForm = function(plugin) {
|
||||
$('.context-plugin-forms > .context-plugin-form.active-form', this.form).removeClass('active-form');
|
||||
$('.context-plugin-forms > .context-plugin-form-'+plugin, this.form).addClass('active-form');
|
||||
$('.context-plugin-list > li > a').removeClass('active-form');
|
||||
$('.context-plugin-list > li.context-plugin-'+plugin+' > a').addClass('active-form');
|
||||
return this;
|
||||
};
|
||||
|
||||
// Show a plugin form.
|
||||
this.hideForm = function(plugin) {
|
||||
$('.context-plugin-forms > .context-plugin-form-'+plugin, this.form).removeClass('active-form');
|
||||
$('.context-plugin-list > li.context-plugin-'+plugin+' > a').removeClass('active-form');
|
||||
return this;
|
||||
};
|
||||
|
||||
// Select handler.
|
||||
$('.context-plugin-selector select', this.form).change(function() {
|
||||
var plugins = $(this).parents('div.context-plugins').data('contextPlugins');
|
||||
if (plugins) {
|
||||
var plugin = $(this).val();
|
||||
plugins.addPlugin(plugin);
|
||||
}
|
||||
});
|
||||
|
||||
// Show form handler.
|
||||
$('.context-plugin-list > li > a', this.form).click(function() {
|
||||
var plugins = $(this).parents('div.context-plugins').data('contextPlugins');
|
||||
if (plugins) {
|
||||
var plugin = $(this).attr('href').split('#context-plugin-form-')[1];
|
||||
plugins.showForm(plugin);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Remove handler.
|
||||
$('.context-plugin-list span.remove', this.form).click(function() {
|
||||
var plugins = $(this).parents('div.context-plugins').data('contextPlugins');
|
||||
if (plugins) {
|
||||
var plugin = $(this).parent().attr('href').split('#context-plugin-form-')[1];
|
||||
plugins.removePlugin(plugin);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Set the plugin states.
|
||||
this.setState();
|
||||
}
|
||||
|
||||
Drupal.behaviors.context_ui = function(context) {
|
||||
// Initialize context plugin form.
|
||||
$('form div.context-plugins:not(.context-ui-processed)').each(function() {
|
||||
$(this).addClass('context-ui-processed');
|
||||
$(this).data('contextPlugins', new DrupalContextPlugins($(this)));
|
||||
});
|
||||
|
||||
// Initialize context editor.
|
||||
if (jQuery().pageEditor) {
|
||||
$('form.context-editor:not(.context-ui-processed)')
|
||||
.addClass('context-ui-processed')
|
||||
.pageEditor()
|
||||
.each(function() {
|
||||
var editor = $(this);
|
||||
var defaultContext = $('li.context-editable', this).attr('id').split('context-editable-trigger-')[1];
|
||||
$(this).data('defaultContext', defaultContext);
|
||||
|
||||
// Attach start/end handlers to editable contexts.
|
||||
$('li.context-editable a.edit', editor).click(function() {
|
||||
var trigger = $(this).parents('li.context-editable').addClass('context-editing');
|
||||
var context = trigger.attr('id').split('context-editable-trigger-')[1];
|
||||
editor.pageEditor('start', context);
|
||||
return false;
|
||||
});
|
||||
$('li.context-editable a.done', editor).click(function() {
|
||||
editor.pageEditor('end');
|
||||
return false;
|
||||
});
|
||||
$(editor).submit(function() {
|
||||
if (editor.pageEditor('isEditing')) {
|
||||
editor.pageEditor('end');
|
||||
}
|
||||
});
|
||||
|
||||
// Handler for start event.
|
||||
editor.bind('start.pageEditor', function(event, context) {
|
||||
// Fallback to first context if param is empty.
|
||||
if (!context) {
|
||||
context = $(this).data('defaultContext');
|
||||
$('li#context-editable-trigger-'+context, this).addClass('context-editing');
|
||||
}
|
||||
$(document.body).addClass('context-editing');
|
||||
$('#context-editable-'+context, this).show();
|
||||
});
|
||||
|
||||
// Handler for end event.
|
||||
editor.bind('end.pageEditor', function(event, context) {
|
||||
$(document.body).removeClass('context-editing');
|
||||
$('div.contexts div.context-editable', this).hide();
|
||||
$('li.context-editable').removeClass('context-editing');
|
||||
$('form.context-editor').addClass('edited');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,282 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implementation of hook_ctools_plugin_directory().
|
||||
*/
|
||||
function context_ui_ctools_plugin_directory($module, $plugin) {
|
||||
if ($module == 'ctools' && $plugin == 'export_ui') {
|
||||
return 'export_ui';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_theme().
|
||||
*/
|
||||
function context_ui_theme() {
|
||||
$items = array();
|
||||
$items['context_ui_form'] = array(
|
||||
'arguments' => array('form' => array()),
|
||||
'path' => drupal_get_path('module', 'context_ui') .'/theme',
|
||||
'template' => 'context-ui-form',
|
||||
'file' => 'theme.inc',
|
||||
);
|
||||
$items['context_ui_plugins'] = array(
|
||||
'arguments' => array('form' => array()),
|
||||
'path' => drupal_get_path('module', 'context_ui') .'/theme',
|
||||
'template' => 'context-ui-plugins',
|
||||
'file' => 'theme.inc',
|
||||
);
|
||||
$items['context_ui_editor'] = array(
|
||||
'arguments' => array('form' => array()),
|
||||
'path' => drupal_get_path('module', 'context_ui') .'/theme',
|
||||
'template' => 'context-ui-editor',
|
||||
'file' => 'theme.inc',
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_block().
|
||||
*/
|
||||
function context_ui_block($op = 'list', $delta = 0, $edit = array()) {
|
||||
switch ($op) {
|
||||
case 'list':
|
||||
$blocks = array();
|
||||
if (module_exists('jquery_ui') && module_exists('admin')) {
|
||||
$blocks['editor'] = array('info' => t('Context editor'), 'admin' => TRUE);
|
||||
}
|
||||
if (module_exists('devel')) {
|
||||
$blocks['devel'] = array('info' => t('Context inspector'), 'admin' => TRUE);
|
||||
}
|
||||
return $blocks;
|
||||
case 'view':
|
||||
switch ($delta) {
|
||||
case 'editor':
|
||||
if (user_access('administer site configuration') && strpos($_GET['q'], 'admin/build/context') === FALSE && $contexts = context_active_contexts()) {
|
||||
return array(
|
||||
'subject' => t('Context editor'),
|
||||
'content' => drupal_get_form('context_ui_editor', $contexts),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'devel':
|
||||
if (module_exists('devel') && $all = context_get()) {
|
||||
return array(
|
||||
'subject' => t('Context inspector'),
|
||||
'content' => kdevel_print_object($all),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_menu().
|
||||
*/
|
||||
function context_ui_menu() {
|
||||
$items = array();
|
||||
$items['admin/build/context/settings'] = array(
|
||||
'title' => 'Settings',
|
||||
'access callback' => 'user_access',
|
||||
'access arguments' => array('administer site configuration'),
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('context_ui_settings'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 3,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_help().
|
||||
*/
|
||||
function context_ui_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#context_ui':
|
||||
$output = file_get_contents(drupal_get_path('module', 'context_ui') .'/README.txt');
|
||||
return module_exists('markdown') ? filter_xss_admin(module_invoke('markdown', 'filter', 'process', 0, -1, $output)) : '<pre>'. check_plain($output) .'</pre>';
|
||||
case 'admin/build/context':
|
||||
return '<p>'. t('Context allows you to manage contextual conditions and reactions for different portions of your site. You can think of each context as representing a "section" of your site. For each context, you can choose the conditions that trigger this context to be active and choose different aspects of Drupal that should react to this active context.') .'</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline context editor form.
|
||||
*/
|
||||
function context_ui_editor($form_state, $contexts) {
|
||||
$form = array(
|
||||
'#attributes' => array('class' => 'context-editor'),
|
||||
'#theme' => array('context_ui_editor'),
|
||||
'editables' => array('#type' => 'markup'),
|
||||
'contexts' => array('#tree' => TRUE),
|
||||
'buttons' => array('#tree' => FALSE),
|
||||
);
|
||||
|
||||
$items = array();
|
||||
$form_context = array();
|
||||
ksort($contexts);
|
||||
|
||||
foreach ($contexts as $context) {
|
||||
$edit = l(t('Edit'), $_GET['q'], array('fragment' => $context->name, 'attributes' => array('class' => 'edit')));
|
||||
$done = l(t('Done'), $_GET['q'], array('fragment' => $context->name, 'attributes' => array('class' => 'done')));
|
||||
$items[] = array(
|
||||
'data' => "<div class='label'>" . (empty($context->description) ? $context->name : check_plain($context->description)) ."</div><div class='links'>{$edit} {$done}</div>",
|
||||
'class' => 'context-editable clear-block',
|
||||
'id' => "context-editable-trigger-{$context->name}",
|
||||
);
|
||||
$form_context = array(
|
||||
'#tree' => TRUE,
|
||||
'#type' => module_exists('admin') ? 'admin_panes' : NULL,
|
||||
'context' => array('#type' => 'value', '#value' => $context),
|
||||
);
|
||||
|
||||
// Edit context conditions.
|
||||
foreach (array_keys(context_conditions()) as $condition) {
|
||||
$plugin = context_get_plugin('condition', $condition);
|
||||
if (method_exists($plugin, 'editor_form') && ($plugin_form = $plugin->editor_form($context))) {
|
||||
$form_context['condition'][$condition] = $plugin_form;
|
||||
}
|
||||
}
|
||||
if (count(element_children($form_context['condition']))) {
|
||||
$form_context['condition']['#title'] = t('Conditions');
|
||||
$form_context['condition']['#type'] = 'item';
|
||||
$form_context['condition']['#description'] = t('This context is active when any of the selected conditions are true.');
|
||||
}
|
||||
|
||||
// Edit context reactions.
|
||||
foreach (array_keys(context_reactions()) as $reaction) {
|
||||
$plugin = context_get_plugin('reaction', $reaction);
|
||||
if (method_exists($plugin, 'editor_form') && ($plugin_form = $plugin->editor_form($context))) {
|
||||
$form_context["reaction-{$reaction}"] = $plugin_form + array('#title' => $plugin->title);
|
||||
}
|
||||
}
|
||||
|
||||
// Add to main form.
|
||||
$form['contexts'][$context->name] = $form_context;
|
||||
}
|
||||
|
||||
// Display editable contexts in list.
|
||||
$form['editables']['#value'] = theme('item_list', $items);
|
||||
|
||||
// Buttons.
|
||||
$form['buttons']['save'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save changes'),
|
||||
'#submit' => array('context_ui_editor_submit'),
|
||||
);
|
||||
$form['buttons']['cancel'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Cancel'),
|
||||
'#submit' => array('context_ui_editor_cancel'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Values processor for context_ui_editor_submit().
|
||||
* Split out for reuse by overriding submit handlers.
|
||||
*/
|
||||
function context_ui_editor_process($values) {
|
||||
$context = $values['context'];
|
||||
foreach (array_keys(context_conditions()) as $condition) {
|
||||
if (isset($values['condition'][$condition])) {
|
||||
$plugin = context_get_plugin('condition', $condition);
|
||||
if ($plugin && method_exists($plugin, 'editor_form_submit')) {
|
||||
$context->conditions[$condition]['values'] = $plugin->editor_form_submit($context, $values['condition'][$condition]);
|
||||
}
|
||||
}
|
||||
if (isset($context->conditions[$condition]) && context_empty($context->conditions[$condition]['values'])) {
|
||||
unset($context->conditions[$condition]);
|
||||
}
|
||||
}
|
||||
foreach (array_keys(context_reactions()) as $reaction) {
|
||||
if (isset($values["reaction-{$reaction}"])) {
|
||||
$plugin = context_get_plugin('reaction', $reaction);
|
||||
if ($plugin && method_exists($plugin, 'editor_form_submit')) {
|
||||
$context->reactions[$reaction] = $plugin->editor_form_submit($context, $values["reaction-{$reaction}"]);
|
||||
}
|
||||
}
|
||||
if (isset($context->reactions[$reaction]) && context_empty($context->reactions[$reaction])) {
|
||||
unset($context->reactions[$reaction]);
|
||||
}
|
||||
}
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save handler for context_block_editor().
|
||||
*/
|
||||
function context_ui_editor_submit(&$form, &$form_state) {
|
||||
foreach ($form_state['values']['contexts'] as $name => $values) {
|
||||
$original_conditions = $values['context']->conditions;
|
||||
$original_reactions = $values['context']->reactions;
|
||||
$context = context_ui_editor_process($values);
|
||||
if (($original_conditions !== $context->conditions) || ($original_reactions !== $context->reactions)) {
|
||||
if (context_save($context)) {
|
||||
drupal_set_message(t('Saved %title.', array(
|
||||
'%title' => (!empty($context->description) ? $context->description : $context->name)
|
||||
)));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Could not save context %title.', array('%title' => $context->name)), 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel handler for context_block_editor().
|
||||
*/
|
||||
function context_ui_editor_cancel(&$form, &$form_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings form.
|
||||
*/
|
||||
function context_ui_settings(&$form_state) {
|
||||
$form = array();
|
||||
foreach (context_conditions() as $condition => $info) {
|
||||
if ($plugin = context_get_plugin('condition', $condition)) {
|
||||
$settings_form = $plugin->settings_form();
|
||||
if ($settings_form) {
|
||||
$form['conditions'][$reaction] = $settings_form;
|
||||
$form['conditions'][$reaction]['#tree'] = FALSE;
|
||||
$form['conditions'][$reaction]['#type'] = 'fieldset';
|
||||
$form['conditions'][$reaction]['#title'] = $info['title'];
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (context_reactions() as $reaction => $info) {
|
||||
if ($plugin = context_get_plugin('reaction', $reaction)) {
|
||||
$settings_form = $plugin->settings_form();
|
||||
if ($settings_form) {
|
||||
$form['reactions'][$reaction] = $settings_form;
|
||||
$form['reactions'][$reaction]['#tree'] = FALSE;
|
||||
$form['reactions'][$reaction]['#type'] = 'fieldset';
|
||||
$form['reactions'][$reaction]['#title'] = $info['title'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$form = system_settings_form($form);
|
||||
$form['#submit'][] = 'context_ui_settings_submit';
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra submit handler for context_ui_settings.
|
||||
* Mark the menu cache as needing a rebuild.
|
||||
*/
|
||||
function context_ui_settings_submit($form, &$form_state) {
|
||||
variable_set('menu_rebuild_needed', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_perm
|
||||
*/
|
||||
function context_perm() {
|
||||
return array('context ajax block access');
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
$plugin = array(
|
||||
'schema' => 'context',
|
||||
'menu' => array(
|
||||
'menu prefix' => 'admin/build',
|
||||
'menu item' => 'context',
|
||||
'menu title' => 'Context',
|
||||
'menu description' => 'Associate menus, views, blocks, etc. with different contexts to structure your site.',
|
||||
),
|
||||
'title singular' => t('context'),
|
||||
'title singular proper' => t('Context'),
|
||||
'title plural' => t('contexts'),
|
||||
'title plural proper' => t('Contexts'),
|
||||
'form' => array(
|
||||
'settings' => 'context_ui_form',
|
||||
'submit' => 'context_ui_form_submit',
|
||||
),
|
||||
'handler' => array(
|
||||
'class' => 'context_export_ui',
|
||||
'parent' => 'ctools_export_ui',
|
||||
),
|
||||
);
|
|
@ -0,0 +1,255 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* CTools export UI extending class. Slightly customized for Context.
|
||||
*/
|
||||
class context_export_ui extends ctools_export_ui {
|
||||
function list_form(&$form, &$form_state) {
|
||||
parent::list_form($form, $form_state);
|
||||
$form['top row']['submit'] = $form['bottom row']['submit'];
|
||||
$form['top row']['reset'] = $form['bottom row']['reset'];
|
||||
$form['bottom row']['#access'] = FALSE;
|
||||
// Invalidate the context cache.
|
||||
context_invalidate_cache();
|
||||
return;
|
||||
}
|
||||
|
||||
function list_css() {
|
||||
ctools_add_css('export-ui-list');
|
||||
drupal_add_css(drupal_get_path("module", "context_ui") ."/context_ui.css");
|
||||
}
|
||||
|
||||
function list_render(&$form_state) {
|
||||
return theme('table', $this->list_table_header(), $this->rows, array('class' => 'context-admin', 'id' => 'ctools-export-ui-list-items'));
|
||||
}
|
||||
|
||||
function list_build_row($item, &$form_state, $operations) {
|
||||
$name = $item->name;
|
||||
|
||||
// Add a row for tags.
|
||||
$tag = !empty($item->tag) ? $item->tag : t('< Untagged >');
|
||||
if (!isset($this->rows[$tag])) {
|
||||
$this->rows[$tag]['data'] = array();
|
||||
$this->rows[$tag]['data'][] = array('data' => check_plain($tag), 'colspan' => 3, 'class' => 'tag');
|
||||
$this->sorts["{$tag}"] = $tag;
|
||||
}
|
||||
|
||||
// Build row for each context item.
|
||||
$this->rows["{$tag}:{$name}"]['data'] = array();
|
||||
$this->rows["{$tag}:{$name}"]['class'] = !empty($item->disabled) ? 'ctools-export-ui-disabled' : 'ctools-export-ui-enabled';
|
||||
$this->rows["{$tag}:{$name}"]['data'][] = array(
|
||||
'data' => check_plain($name) . "<div class='description'>" . check_plain($item->description) . "</div>",
|
||||
'class' => 'ctools-export-ui-name'
|
||||
);
|
||||
$this->rows["{$tag}:{$name}"]['data'][] = array(
|
||||
'data' => check_plain($item->type),
|
||||
'class' => 'ctools-export-ui-storage'
|
||||
);
|
||||
$this->rows["{$tag}:{$name}"]['data'][] = array(
|
||||
'data' => theme('links', $operations, array('class' => 'links inline')),
|
||||
'class' => 'ctools-export-ui-operations'
|
||||
);
|
||||
|
||||
// Sort by tag, name.
|
||||
$this->sorts["{$tag}:{$name}"] = $tag . $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of edit_form_submit().
|
||||
* Don't copy values from $form_state['values'].
|
||||
*/
|
||||
function edit_form_submit(&$form, &$form_state) {
|
||||
if (!empty($this->plugin['form']['submit'])) {
|
||||
$this->plugin['form']['submit']($form, $form_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates the omnibus context definition editing form.
|
||||
*
|
||||
* @param $op
|
||||
* The type of form to build. Either "add", "view" or "edit"
|
||||
* @param $cid
|
||||
* The db context identifier - required when $op == "edit"
|
||||
*
|
||||
* @return
|
||||
* A Drupal form array.
|
||||
*/
|
||||
function context_ui_form(&$form, &$form_state) {
|
||||
$context = $form_state['item'];
|
||||
$form['#base'] = 'context_ui_form';
|
||||
$form['#theme'] = 'context_ui_form';
|
||||
|
||||
// Core context definition
|
||||
$form['info']['#type'] = 'fieldset';
|
||||
$form['info']['#tree'] = FALSE;
|
||||
|
||||
// Swap out name validator. Allow dashes.
|
||||
if (isset($form['info']['name']['#element_validate'])) {
|
||||
$form['info']['name']['#element_validate'] = array('context_ui_edit_name_validate');
|
||||
}
|
||||
|
||||
$form['info']['tag'] = array(
|
||||
'#title' => t('Tag'),
|
||||
'#type' => 'textfield',
|
||||
'#required' => FALSE,
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => isset($context->tag) ? $context->tag : '',
|
||||
'#description' => t('Example: <code>theme</code>') .'<br/>'. t('A tag to group this context with others.'),
|
||||
);
|
||||
|
||||
$form['info']['description'] = array(
|
||||
'#title' => t('Description'),
|
||||
'#type' => 'textfield',
|
||||
'#required' => FALSE,
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => isset($context->description) ? $context->description: '',
|
||||
'#description' => t('The description of this context definition.'),
|
||||
);
|
||||
|
||||
// Condition mode
|
||||
$form['condition_mode'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => isset($context->condition_mode) ? $context->condition_mode : FALSE,
|
||||
'#title' => t('Require all conditions'),
|
||||
'#description' => t('If checked, all conditions must be met for this context to be active. Otherwise, the first condition that is met will activate this context.')
|
||||
);
|
||||
|
||||
// Condition plugin forms
|
||||
$form['conditions'] = array(
|
||||
'#theme' => 'context_ui_plugins',
|
||||
'#title' => t('Conditions'),
|
||||
'#description' => t('Trigger the activation of this context'),
|
||||
'#tree' => TRUE,
|
||||
'selector' => array(
|
||||
'#type' => 'select',
|
||||
'#options' => array(0 => '<'. t('Add a condition') .'>'),
|
||||
'#default_value' => 0,
|
||||
),
|
||||
'state' => array(
|
||||
'#attributes' => array('class' => 'context-plugins-state'),
|
||||
'#type' => 'hidden',
|
||||
),
|
||||
'plugins' => array('#tree' => TRUE),
|
||||
);
|
||||
$conditions = array_keys(context_conditions());
|
||||
sort($conditions);
|
||||
foreach ($conditions as $condition) {
|
||||
if ($plugin = context_get_plugin('condition', $condition)) {
|
||||
$form['conditions']['plugins'][$condition] = array(
|
||||
'#tree' => TRUE,
|
||||
'#plugin' => $plugin,
|
||||
'#context_enabled' => isset($context->conditions[$condition]), // This flag is used at the theme layer.
|
||||
'values' => $plugin->condition_form($context),
|
||||
'options' => $plugin->options_form($context),
|
||||
);
|
||||
$form['conditions']['selector']['#options'][$condition] = $plugin->title;
|
||||
}
|
||||
}
|
||||
|
||||
// Reaction plugin forms
|
||||
$form['reactions'] = array(
|
||||
'#theme' => 'context_ui_plugins',
|
||||
'#title' => t('Reactions'),
|
||||
'#description' => t('Actions to take when this context is active'),
|
||||
'#tree' => TRUE,
|
||||
'selector' => array(
|
||||
'#type' => 'select',
|
||||
'#options' => array(0 => '<'. t('Add a reaction') .'>'),
|
||||
'#default_value' => 0,
|
||||
),
|
||||
'state' => array(
|
||||
'#attributes' => array('class' => 'context-plugins-state'),
|
||||
'#type' => 'hidden',
|
||||
),
|
||||
'plugins' => array('#tree' => TRUE),
|
||||
);
|
||||
$reactions = array_keys(context_reactions());
|
||||
sort($reactions);
|
||||
foreach ($reactions as $reaction) {
|
||||
if ($plugin = context_get_plugin('reaction', $reaction)) {
|
||||
$form['reactions']['plugins'][$reaction] = $plugin->options_form($context) + array(
|
||||
'#plugin' => $plugin,
|
||||
'#context_enabled' => isset($context->reactions[$reaction]), // This flag is used at the theme layer.
|
||||
);
|
||||
$form['reactions']['selector']['#options'][$reaction] = $plugin->title;
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies a context object from submitted form values.
|
||||
*
|
||||
* @param $context
|
||||
* The context object to modify.
|
||||
* @param $form
|
||||
* A form array with submitted values
|
||||
*
|
||||
* @return
|
||||
* A context object
|
||||
*/
|
||||
function context_ui_form_process($context, $form) {
|
||||
$context->name = isset($form['name']) ? $form['name'] : NULL;
|
||||
$context->description = isset($form['description']) ? $form['description'] : NULL;
|
||||
$context->tag = isset($form['tag']) ? $form['tag'] : NULL;
|
||||
$context->condition_mode = isset($form['condition_mode']) ? $form['condition_mode'] : NULL;
|
||||
$context->conditions = array();
|
||||
$context->reactions = array();
|
||||
if (!empty($form['conditions'])) {
|
||||
$enabled = explode(',', $form['conditions']['state']);
|
||||
foreach ($form['conditions']['plugins'] as $condition => $values) {
|
||||
if (in_array($condition, $enabled, TRUE) && ($plugin = context_get_plugin('condition', $condition))) {
|
||||
if (isset($values['values'])) {
|
||||
$context->conditions[$condition]['values'] = $plugin->condition_form_submit($values['values']);
|
||||
}
|
||||
if (isset($values['options'])) {
|
||||
$context->conditions[$condition]['options'] = $plugin->options_form_submit($values['options']);
|
||||
}
|
||||
if (context_empty($context->conditions[$condition]['values'])) {
|
||||
unset($context->conditions[$condition]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($form['reactions'])) {
|
||||
$enabled = explode(',', $form['reactions']['state']);
|
||||
foreach ($form['reactions']['plugins'] as $reaction => $values) {
|
||||
if (in_array($reaction, $enabled, TRUE) && ($plugin = context_get_plugin('reaction', $reaction))) {
|
||||
if (isset($values)) {
|
||||
$context->reactions[$reaction] = $plugin->options_form_submit($values);
|
||||
}
|
||||
if (context_empty($context->reactions[$reaction])) {
|
||||
unset($context->reactions[$reaction]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for main context_ui form.
|
||||
*/
|
||||
function context_ui_form_submit($form, &$form_state) {
|
||||
$form_state['item'] = context_ui_form_process($form_state['item'], $form_state['values']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for ctools_export_ui_edit_name_validate(). Allow dashes.
|
||||
*/
|
||||
function context_ui_edit_name_validate($element, &$form_state) {
|
||||
$plugin = $form_state['plugin'];
|
||||
// Check for string identifier sanity
|
||||
if (!preg_match('!^[a-z0-9_-]+$!', $element['#value'])) {
|
||||
form_error($element, t('The export id can only consist of lowercase letters, underscores, dashes, and numbers.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for name collision
|
||||
if (empty($form_state['item']->export_ui_allow_overwrite) && $exists = ctools_export_crud_load($plugin['schema'], $element['#value'])) {
|
||||
form_error($element, t('A @plugin with this name already exists. Please choose another name or delete the existing item before creating a new one.', array('@plugin' => $plugin['title singular'])));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
/**
|
||||
* Generic pageEditor plugin. Allows an editor DOM object to trigger
|
||||
* init, start, and end events. Implementors can check whether the
|
||||
* editor is currently editing and bind handlers for the events triggered
|
||||
* by the editor.
|
||||
*/
|
||||
(function($) {
|
||||
$.fn.pageEditor = function(method, data) {
|
||||
this.each(function() {
|
||||
switch (method) {
|
||||
case 'isEditing':
|
||||
return this.editing;
|
||||
case 'start':
|
||||
if (!this.inited) {
|
||||
this.inited = true;
|
||||
$(this).trigger('init.pageEditor', data);
|
||||
}
|
||||
this.editing = true;
|
||||
$(this).trigger('start.pageEditor', data);
|
||||
break;
|
||||
case 'end':
|
||||
if (!this.inited) {
|
||||
this.inited = true;
|
||||
$(this).trigger('init.pageEditor', data);
|
||||
}
|
||||
this.editing = false;
|
||||
$(this).trigger('end.pageEditor', data);
|
||||
break;
|
||||
default:
|
||||
this.inited = false;
|
||||
this.editing = false;
|
||||
break;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};
|
||||
})(jQuery);
|
|
@ -0,0 +1 @@
|
|||
if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?'0'+n:n}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z':null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key)}if(typeof rep==='function'){value=rep.call(holder,key,value)}switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null'}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null'}v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v}if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v)}}}}v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' '}}else if(typeof space==='string'){indent=space}rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify')}return str('',{'':value})}}if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j}throw new SyntaxError('JSON.parse')}}}());
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Functional Test for Context UI
|
||||
*
|
||||
* TODO Test if menu and blocks respond.
|
||||
*/
|
||||
|
||||
class ContextUiTestCase extends DrupalWebTestCase {
|
||||
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Context UI functional tests'),
|
||||
'description' => t('Create and save a context.') ,
|
||||
'group' => t('Context UI'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('ctools', 'context', 'context_ui');
|
||||
|
||||
// Create and login user
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer blocks', 'access content', 'create page content'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
function testCreateContext() {
|
||||
// Create context
|
||||
$context = new stdClass();
|
||||
$context->name = strtolower($this->randomName(15));
|
||||
$context->description = strtolower($this->randomName(15));
|
||||
$context->tag = strtolower($this->randomName(15));
|
||||
$this->context = $context;
|
||||
|
||||
$edit = array(
|
||||
'name' => $context->name,
|
||||
'description' => $context->description,
|
||||
'tag' => $context->tag,
|
||||
'conditions[plugins][node][values][page]' => 'page',
|
||||
'reactions[plugins][menu]' => 'node/add/page',
|
||||
);
|
||||
$this->drupalPost('admin/build/context/add', $edit, 'Save');
|
||||
$this->assertText($context->name . ' has been created.', 'Context saved.');
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<div class='context-editor clear-block'>
|
||||
<?php print drupal_render($form) ?>
|
||||
<div class='contexts'>
|
||||
<?php foreach (element_children($contexts) as $context): ?>
|
||||
<div class='context-editable' id='context-editable-<?php print $context ?>'><?php print drupal_render($contexts[$context]) ?></div>
|
||||
<?php endforeach; ?>
|
||||
<?php print drupal_render($contexts) ?>
|
||||
</div>
|
||||
<div class='buttons'><?php print drupal_render($buttons) ?></div>
|
||||
</div>
|
|
@ -0,0 +1,2 @@
|
|||
<?php print drupal_render($form) ?>
|
||||
<div class='buttons'><?php print drupal_render($buttons) ?></div>
|
|
@ -0,0 +1,22 @@
|
|||
<div class='context-plugins clear-block'>
|
||||
<div class='context-plugin-forms'>
|
||||
<?php foreach (element_children($form['plugins']) as $plugin): ?>
|
||||
<div class='context-plugin-form context-plugin-form-<?php print $plugin ?>'>
|
||||
<?php print drupal_render($form['plugins'][$plugin]) ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class='context-plugin-selector'>
|
||||
<div class='context-plugin-info'>
|
||||
<h2 class='context-plugin-title'><?php print $title ?></h2>
|
||||
<div class='description'><?php print $description ?></div>
|
||||
<?php print drupal_render($form['selector']) ?>
|
||||
<?php print drupal_render($form['state']) ?>
|
||||
</div>
|
||||
<?php print theme('links', $plugins, array('class' => 'context-plugin-list')) ?>
|
||||
</div>
|
||||
|
||||
<?php print drupal_render($form) ?>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('context_ui_editor').
|
||||
*/
|
||||
function template_preprocess_context_ui_editor(&$vars) {
|
||||
drupal_add_css(drupal_get_path('module', 'context_ui') . '/context_ui.css');
|
||||
drupal_add_js(drupal_get_path('module', 'context_ui') . '/context_ui.js');
|
||||
drupal_add_js(drupal_get_path('module', 'context_ui') . '/jquery.pageEditor.js');
|
||||
|
||||
$vars['contexts'] = $vars['form']['contexts'];
|
||||
unset($vars['form']['contexts']);
|
||||
|
||||
$vars['buttons'] = $vars['form']['buttons'];
|
||||
unset($vars['form']['buttons']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('context_ui_plugins').
|
||||
*/
|
||||
function template_preprocess_context_ui_plugins(&$vars) {
|
||||
drupal_add_css(drupal_get_path("module", "context_ui") ."/context_ui.css");
|
||||
drupal_add_js(drupal_get_path("module", "context_ui") ."/context_ui.js");
|
||||
drupal_add_js(drupal_get_path('module', 'context_ui') . '/jquery.pageEditor.js');
|
||||
|
||||
// Provide title & desc.
|
||||
$vars['title'] = check_plain($vars['form']['#title']);
|
||||
$vars['description'] = check_plain($vars['form']['#description']);
|
||||
|
||||
// Build list of plugins.
|
||||
$plugins = array();
|
||||
$vars['plugins'] = array();
|
||||
foreach (element_children($vars['form']['plugins']) as $plugin) {
|
||||
$link = array(
|
||||
'title' => $vars['form']['plugins'][$plugin]['#plugin']->title . "<span class='remove'>". t('Remove') ."</span>",
|
||||
'href' => $_GET['q'],
|
||||
'html' => TRUE,
|
||||
'fragment' => "context-plugin-form-{$plugin}",
|
||||
);
|
||||
$class = $vars['form']['plugins'][$plugin]['#context_enabled'] ? "context-plugin-{$plugin}" : "context-plugin-{$plugin} disabled";
|
||||
$vars['plugins'][$class] = $link;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('context_ui_form').
|
||||
*/
|
||||
function template_preprocess_context_ui_form(&$vars) {
|
||||
drupal_add_css(drupal_get_path("module", "context_ui") ."/context_ui.css");
|
||||
drupal_add_js(drupal_get_path("module", "context_ui") ."/context_ui.js");
|
||||
drupal_add_js(drupal_get_path('module', 'context_ui') . '/jquery.pageEditor.js');
|
||||
$vars['buttons'] = $vars['form']['buttons'];
|
||||
unset($vars['form']['buttons']);
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Base class for a context condition.
|
||||
*/
|
||||
class context_condition {
|
||||
var $plugin;
|
||||
var $title;
|
||||
var $description;
|
||||
var $values = array();
|
||||
|
||||
/**
|
||||
* Clone our references when we're being cloned.
|
||||
*
|
||||
* PHP 5.3 performs 'shallow' clones when clone()'ing objects, meaning that
|
||||
* any objects or arrays referenced by this object will not be copied, the
|
||||
* cloned object will just reference our objects/arrays instead. By iterating
|
||||
* over our properties and serializing and unserializing them, we force PHP to
|
||||
* copy them.
|
||||
*/
|
||||
function __clone() {
|
||||
foreach ($this as $key => $val) {
|
||||
if (is_object($val) || (is_array($val))) {
|
||||
$this->{$key} = unserialize(serialize($val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Do not override.
|
||||
*/
|
||||
function __construct($plugin, $info) {
|
||||
$this->plugin = $plugin;
|
||||
$this->title = isset($info['title']) ? $info['title'] : $plugin;
|
||||
$this->description = isset($info['description']) ? $info['description'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition values.
|
||||
*/
|
||||
function condition_values() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition form.
|
||||
*/
|
||||
function condition_form($context) {
|
||||
return array(
|
||||
'#title' => $this->title,
|
||||
'#description' => $this->description,
|
||||
'#options' => $this->condition_values(),
|
||||
'#type' => 'checkboxes',
|
||||
'#default_value' => $this->fetch_from_context($context, 'values'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition form submit handler.
|
||||
*/
|
||||
function condition_form_submit($values) {
|
||||
ksort($values);
|
||||
|
||||
// Editor forms are generally checkboxes -- do some checkbox processing.
|
||||
return drupal_map_assoc(array_keys(array_filter($values)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Options form. Provide additional options for your condition.
|
||||
*/
|
||||
function options_form($context) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Options form submit handler.
|
||||
*/
|
||||
function options_form_submit($values) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings form. Provide variable settings for your condition.
|
||||
*/
|
||||
function settings_form() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Context editor form for conditions.
|
||||
*/
|
||||
function editor_form($context = NULL) {
|
||||
$form = array();
|
||||
if (!empty($this->values)) {
|
||||
$options = $this->condition_values();
|
||||
foreach ($this->values as $value => $contexts) {
|
||||
$label = "{$this->title}: ";
|
||||
$label .= isset($options[$value]) ? trim($options[$value], ' -') : $value;
|
||||
$form[$value] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => check_plain($label),
|
||||
'#default_value' => empty($context->name) ? TRUE : in_array($context->name, $contexts, TRUE),
|
||||
);
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context editor form submit handler.
|
||||
*/
|
||||
function editor_form_submit(&$context, $values) {
|
||||
// Merge existing values in from non-active conditions.
|
||||
$existing = $this->fetch_from_context($context, 'values');
|
||||
$values += !empty($existing) ? $existing : array();
|
||||
|
||||
ksort($values);
|
||||
|
||||
// Editor forms are generally checkboxes -- do some checkbox processing.
|
||||
return drupal_map_assoc(array_keys(array_filter($values)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method that is called from hooks or other integration points with
|
||||
* Drupal. Note that it is not implemented in the base class, allowing
|
||||
* extending classes to change the function signature if necessary.
|
||||
*
|
||||
* function execute($value) {
|
||||
* foreach ($this->get_contexts($value) as $context) {
|
||||
* $this->condition_met($context, $value);
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Marks a context as having met this particular condition.
|
||||
*/
|
||||
function condition_met($context, $value = NULL) {
|
||||
if (isset($value)) {
|
||||
$this->values[$value] = isset($this->values[$value]) ? $this->values[$value] : array();
|
||||
$this->values[$value][] = $context->name;
|
||||
}
|
||||
context_condition_met($context, $this->plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this condition is used by any contexts. Can be used to
|
||||
* prevent expensive condition checks from being triggered when no contexts
|
||||
* use this condition.
|
||||
*/
|
||||
function condition_used() {
|
||||
$map = context_condition_map();
|
||||
return !empty($map[$this->plugin]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all contexts with the condition value provided.
|
||||
*/
|
||||
function get_contexts($value = NULL) {
|
||||
$map = context_condition_map();
|
||||
$map = isset($map[$this->plugin]) ? $map[$this->plugin] : array();
|
||||
|
||||
$contexts = array();
|
||||
if (isset($value) && (is_string($value) || is_numeric($value))) {
|
||||
if (isset($map[$value]) && is_array($map[$value])) {
|
||||
foreach ($map[$value] as $name) {
|
||||
if (!isset($contexts[$name])) {
|
||||
$context = context_load($name);
|
||||
$contexts[$context->name] = $context;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach ($map as $submap) {
|
||||
foreach ($submap as $name) {
|
||||
if (!isset($contexts[$name])) {
|
||||
$context = context_load($name);
|
||||
$contexts[$context->name] = $context;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve options from the context provided.
|
||||
*/
|
||||
function fetch_from_context($context, $key = NULL) {
|
||||
if (isset($key)) {
|
||||
return isset($context->conditions[$this->plugin][$key]) ? $context->conditions[$this->plugin][$key] : array();
|
||||
}
|
||||
return isset($context->conditions[$this->plugin]) ? $context->conditions[$this->plugin] : array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose book properties as a context condition.
|
||||
*/
|
||||
class context_condition_book extends context_condition {
|
||||
function condition_values() {
|
||||
$values = array();
|
||||
foreach (book_get_books() as $book) {
|
||||
$values[$book['menu_name']] = check_plain($book['title']);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
function execute($node, $op) {
|
||||
if (isset($node->book, $node->book['menu_name'])) {
|
||||
foreach ($this->get_contexts($node->book['menu_name']) as $context) {
|
||||
$this->condition_met($context, $node->book['menu_name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Set the context on the basis of the node type of page's book root.
|
||||
*/
|
||||
class context_condition_bookroot extends context_condition_node {
|
||||
function execute($node, $op) {
|
||||
if ($this->condition_used() && !empty($node->book['bid'])) {
|
||||
$type = db_result(db_query("SELECT type FROM {node} WHERE nid = %d", $node->book['bid']));
|
||||
$book = new stdClass();
|
||||
$book->type = $type;
|
||||
parent::execute($book, $op);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose active contexts as a context condition.
|
||||
*/
|
||||
class context_condition_context extends context_condition_path {
|
||||
function execute() {
|
||||
if ($this->condition_used()) {
|
||||
$active_contexts = array_keys(context_active_contexts());
|
||||
foreach ($this->get_contexts() as $context) {
|
||||
if (!in_array($context->name, $active_contexts, TRUE) && $values = $this->fetch_from_context($context, 'values')) {
|
||||
if ($this->match($active_contexts, $values)) {
|
||||
$this->condition_met($context);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the list of active contexts has changed, we need to recurse.
|
||||
if ($active_contexts != array_keys(context_active_contexts())) {
|
||||
$this->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose current language as a context condition.
|
||||
*/
|
||||
class context_condition_language extends context_condition {
|
||||
function condition_values() {
|
||||
return module_exists('locale') ? locale_language_list() : array();
|
||||
}
|
||||
|
||||
function execute($value) {
|
||||
foreach ($this->get_contexts($value) as $context) {
|
||||
$this->condition_met($context, $value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose menu items as a context condition.
|
||||
*/
|
||||
class context_condition_menu extends context_condition {
|
||||
/**
|
||||
* Override of condition_values().
|
||||
*/
|
||||
function condition_values() {
|
||||
$menu_names = variable_get('context_condition_menu_selections', menu_get_menus());
|
||||
$menus = menu_parent_options(array_reverse($menu_names), NULL);
|
||||
$root_menus = array();
|
||||
foreach ($menus as $key => $name) {
|
||||
$id = explode(':', $key);
|
||||
if ($id[1] == '0') {
|
||||
$root_menus[$id[0]] = check_plain($name);
|
||||
}
|
||||
else {
|
||||
$link = menu_link_load($id[1]);
|
||||
$identifier = $link['link_path'];
|
||||
$root_menu = $root_menus[$id[0]];
|
||||
while (isset($menus[$root_menu][$identifier])) {
|
||||
$identifier .= "'";
|
||||
}
|
||||
$menus[$root_menu][$identifier] = $name;
|
||||
}
|
||||
unset($menus[$key]);
|
||||
}
|
||||
array_unshift($menus, "-- ". t('None') ." --");
|
||||
return $menus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of condition_form().
|
||||
* Use multiselect widget.
|
||||
*/
|
||||
function condition_form($context) {
|
||||
$form = parent::condition_form($context);
|
||||
$form['#type'] = 'select';
|
||||
$form['#multiple'] = TRUE;
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of condition_form_submit().
|
||||
* Trim any identifier padding for non-unique path menu items.
|
||||
*/
|
||||
function condition_form_submit($values) {
|
||||
// Trim any identifier padding for non-unique path menu items.
|
||||
$values = parent::condition_form_submit($values);
|
||||
$trimmed = array();
|
||||
foreach ($values as $key => $value) {
|
||||
$trimmed[trim($key, "'")] = trim($value, "'");
|
||||
}
|
||||
return $trimmed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings form for variables.
|
||||
*/
|
||||
function settings_form() {
|
||||
// Get the list of menus in the system.
|
||||
$menus = array_values(menu_get_menus());
|
||||
|
||||
// Convert the list to the format menu_name => menu_name.
|
||||
$options = array_combine($menus, $menus);
|
||||
|
||||
$form = array();
|
||||
$form['context_condition_menu_selections'] = array(
|
||||
'#title' => t('Menus'),
|
||||
'#type' => 'select',
|
||||
'#multiple' => TRUE,
|
||||
'#options' => $options,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => variable_get('context_condition_menu_selections', $options),
|
||||
'#description' => t('Select one or more Drupal menus to use during Menu Context condition checks. If none are selected, all of the menus are used.')
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of execute().
|
||||
*/
|
||||
function execute() {
|
||||
if ($this->condition_used()) {
|
||||
// Menu trail condition integration. Note that because of the way
|
||||
// menu_get_active_trail() is written this will often not work for active
|
||||
// menu items outside the standard navigation tree without the additional
|
||||
// helper code below.
|
||||
if (menu_get_active_menu_name() === 'navigation') {
|
||||
$item = menu_get_item();
|
||||
$menus = variable_get('context_condition_menu_selections', menu_get_menus());
|
||||
|
||||
$params = array_values($menus);
|
||||
$params[] = $item['href'];
|
||||
|
||||
$in_clause = implode(', ', array_fill(0, count($menus), "'%s'"));
|
||||
$query = "SELECT menu_name FROM {menu_links} WHERE menu_name IN ($in_clause) AND link_path = '%s' ORDER BY mlid ASC";
|
||||
|
||||
if ($menu_name = db_result(db_query($query, $params))) {
|
||||
menu_set_active_menu_name($menu_name);
|
||||
}
|
||||
}
|
||||
$trail = menu_get_active_trail();
|
||||
foreach ($trail as $item) {
|
||||
if (!empty($item['href'])) {
|
||||
foreach ($this->get_contexts($item['href']) as $context) {
|
||||
$this->condition_met($context, $item['href']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Trigger context on node view only.
|
||||
*/
|
||||
define('CONTEXT_NODE_VIEW', 0);
|
||||
|
||||
/**
|
||||
* Trigger context on node view and node form.
|
||||
*/
|
||||
define('CONTEXT_NODE_FORM', 1);
|
||||
|
||||
/**
|
||||
* Trigger context on node form only.
|
||||
*/
|
||||
define('CONTEXT_NODE_FORM_ONLY', 2);
|
||||
|
||||
/**
|
||||
* Expose node views/node forms of specific node types as a context condition.
|
||||
*/
|
||||
class context_condition_node extends context_condition {
|
||||
function condition_values() {
|
||||
$values = array();
|
||||
foreach (node_get_types() as $type) {
|
||||
$values[$type->type] = check_plain($type->name);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
function options_form($context) {
|
||||
$defaults = $this->fetch_from_context($context, 'options');
|
||||
return array(
|
||||
'node_form' => array(
|
||||
'#title' => t('Set on node form'),
|
||||
'#type' => 'select',
|
||||
'#options' => array(
|
||||
CONTEXT_NODE_VIEW => t('No'),
|
||||
CONTEXT_NODE_FORM => t('Yes'),
|
||||
CONTEXT_NODE_FORM_ONLY => t('Only on node form')
|
||||
),
|
||||
'#description' => t('Set this context on node forms'),
|
||||
'#default_value' => isset($defaults['node_form']) ? $defaults['node_form'] : TRUE,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function execute($node, $op) {
|
||||
foreach ($this->get_contexts($node->type) as $context) {
|
||||
// Check the node form option.
|
||||
$options = $this->fetch_from_context($context, 'options');
|
||||
if ($op === 'form') {
|
||||
$options = $this->fetch_from_context($context, 'options');
|
||||
if (!empty($options['node_form']) && in_array($options['node_form'], array(CONTEXT_NODE_FORM, CONTEXT_NODE_FORM_ONLY))) {
|
||||
$this->condition_met($context, $node->type);
|
||||
}
|
||||
}
|
||||
elseif (empty($options['node_form']) || $options['node_form'] != CONTEXT_NODE_FORM_ONLY) {
|
||||
$this->condition_met($context, $node->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose node taxonomy terms as a context condition.
|
||||
*/
|
||||
class context_condition_node_taxonomy extends context_condition_node {
|
||||
function condition_values() {
|
||||
$values = array();
|
||||
if (module_exists('taxonomy')) {
|
||||
foreach (taxonomy_get_vocabularies() as $vocab) {
|
||||
if (empty($vocab->tags)) {
|
||||
foreach (taxonomy_get_tree($vocab->vid) as $term) {
|
||||
$values[$term->tid] = check_plain($term->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
function condition_form($context) {
|
||||
$form = parent::condition_form($context);
|
||||
$form['#type'] = 'select';
|
||||
$form['#size'] = 12;
|
||||
$form['#multiple'] = TRUE;
|
||||
$form['#options'] = taxonomy_form_all();
|
||||
return $form;
|
||||
}
|
||||
|
||||
function execute($node, $op) {
|
||||
if ($this->condition_used() && !empty($node->taxonomy)) {
|
||||
foreach ($node->taxonomy as $term) {
|
||||
foreach ($this->get_contexts($term->tid) as $context) {
|
||||
// Check the node form option.
|
||||
if ($op === 'form') {
|
||||
$options = $this->fetch_from_context($context, 'options');
|
||||
if (!empty($options['node_form'])) {
|
||||
$this->condition_met($context, $term->tid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->condition_met($context, $term->tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose paths as a context condition.
|
||||
*/
|
||||
class context_condition_path extends context_condition {
|
||||
/**
|
||||
* Omit condition values. We will provide a custom input form for our conditions.
|
||||
*/
|
||||
function condition_values() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition form.
|
||||
*/
|
||||
function condition_form($context) {
|
||||
$form = parent::condition_form($context);
|
||||
unset($form['#options']);
|
||||
|
||||
$form['#type'] = 'textarea';
|
||||
$form['#default_value'] = implode("\n", $this->fetch_from_context($context, 'values'));
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition form submit handler.
|
||||
*/
|
||||
function condition_form_submit($values) {
|
||||
$parsed = array();
|
||||
$items = explode("\n", $values);
|
||||
if (!empty($items)) {
|
||||
foreach ($items as $v) {
|
||||
$v = trim($v);
|
||||
if (!empty($v)) {
|
||||
$parsed[$v] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute.
|
||||
*/
|
||||
function execute() {
|
||||
if ($this->condition_used()) {
|
||||
// Include both the path alias and normal path for matching.
|
||||
$current_path = array(drupal_get_path_alias($_GET['q']));
|
||||
if ($current_path != $_GET['q']) {
|
||||
$current_path[] = $_GET['q'];
|
||||
}
|
||||
foreach ($this->get_contexts() as $context) {
|
||||
$paths = $this->fetch_from_context($context, 'values');
|
||||
if ($this->match($current_path, $paths, TRUE)) {
|
||||
$this->condition_met($context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the subject against a set of regex patterns.
|
||||
* Similar to drupal_match_path() but also handles negation through the use
|
||||
* of the ~ character.
|
||||
*
|
||||
* @param mixed $subject
|
||||
* The subject string or an array of strings to be matched.
|
||||
* @param array $patterns
|
||||
* An array of patterns. Any patterns that begin with ~ are considered
|
||||
* negative or excluded conditions.
|
||||
* @param boolean $path
|
||||
* Whether the given subject should be matched as a Drupal path. If TRUE,
|
||||
* '<front>' will be replaced with the site frontpage when matching against
|
||||
* $patterns.
|
||||
*/
|
||||
protected function match($subject, $patterns, $path = FALSE) {
|
||||
static $regexps;
|
||||
$match = FALSE;
|
||||
$positives = $negatives = 0;
|
||||
$subject = !is_array($subject) ? array($subject) : $subject;
|
||||
foreach ($patterns as $pattern) {
|
||||
if (strpos($pattern, '~') === 0) {
|
||||
$negate = TRUE;
|
||||
$negatives++;
|
||||
}
|
||||
else {
|
||||
$negate = FALSE;
|
||||
$positives++;
|
||||
}
|
||||
$pattern = ltrim($pattern, '~');
|
||||
if (!isset($regexps[$pattern])) {
|
||||
if ($path) {
|
||||
$regexps[$pattern] = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($pattern, '/')) .')$/';
|
||||
}
|
||||
else {
|
||||
$regexps[$pattern] = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/'), array('|', '.*'), preg_quote($pattern, '/')) .')$/';
|
||||
}
|
||||
}
|
||||
foreach ($subject as $value) {
|
||||
if (preg_match($regexps[$pattern], $value)) {
|
||||
if ($negate) {
|
||||
return FALSE;
|
||||
}
|
||||
$match = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If there are **only** negative conditions and we've gotten this far none
|
||||
// we actually have a match.
|
||||
if ($positives === 0 && $negatives) {
|
||||
return TRUE;
|
||||
}
|
||||
return $match;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Simple sitewide context, always present.
|
||||
*/
|
||||
class context_condition_sitewide extends context_condition {
|
||||
function condition_values() {
|
||||
return array(1 => t('Always active'));
|
||||
}
|
||||
|
||||
function editor_form($context = NULL) {
|
||||
$form = parent::editor_form($context);
|
||||
$form[1]['#title'] = t('Always active');
|
||||
$form['#weight'] = -10;
|
||||
return $form;
|
||||
}
|
||||
|
||||
function execute($value) {
|
||||
foreach ($this->get_contexts($value) as $context) {
|
||||
$this->condition_met($context, $value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose current user role as a context condition.
|
||||
*/
|
||||
class context_condition_user extends context_condition {
|
||||
function condition_values() {
|
||||
$values = array();
|
||||
foreach (user_roles() as $rid => $role_name) {
|
||||
if ($rid == DRUPAL_ANONYMOUS_RID) {
|
||||
$values['anonymous user'] = check_plain($role_name);
|
||||
}
|
||||
elseif ($rid == DRUPAL_AUTHENTICATED_RID) {
|
||||
$values['authenticated user'] = check_plain($role_name);
|
||||
}
|
||||
else {
|
||||
$values[$role_name] = check_plain($role_name);
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
function execute($account) {
|
||||
$roles = $account->roles;
|
||||
foreach ($roles as $rid => $role) {
|
||||
foreach ($this->get_contexts($role) as $context) {
|
||||
$this->condition_met($context, $role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose user pages as a context condition.
|
||||
*/
|
||||
class context_condition_user_page extends context_condition {
|
||||
function condition_values() {
|
||||
$values = array();
|
||||
$values['view'] = t('User profile');
|
||||
$values['form'] = t('User account form');
|
||||
$values['register'] = t('Registration form');
|
||||
return $values;
|
||||
}
|
||||
|
||||
function options_form($context) {
|
||||
$defaults = $this->fetch_from_context($context, 'options');
|
||||
return array(
|
||||
'mode' => array(
|
||||
'#title' => t('Active for'),
|
||||
'#type' => 'select',
|
||||
'#options' => array(
|
||||
'all' => t('Any user'),
|
||||
'current' => t('Only the current user'),
|
||||
'other' => t('Only other users'),
|
||||
),
|
||||
'#default_value' => isset($defaults['mode']) ? $defaults['mode'] : 'all',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function execute($account, $op) {
|
||||
global $user;
|
||||
foreach ($this->get_contexts($op) as $context) {
|
||||
if ($op === 'register') {
|
||||
$this->condition_met($context);
|
||||
}
|
||||
else {
|
||||
$options = $this->fetch_from_context($context, 'options');
|
||||
$mode = !empty($options['mode']) ? $options['mode'] : 'all';
|
||||
switch ($options['mode']) {
|
||||
case 'current':
|
||||
if ($account->uid == $user->uid) {
|
||||
$this->condition_met($context);
|
||||
}
|
||||
break;
|
||||
case 'other':
|
||||
if ($account->uid != $user->uid) {
|
||||
$this->condition_met($context);
|
||||
}
|
||||
break;
|
||||
case 'all':
|
||||
default:
|
||||
$this->condition_met($context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
class context_condition_views extends context_condition {
|
||||
|
||||
/**
|
||||
* Generate a list of database and module provided views.
|
||||
*/
|
||||
function condition_values() {
|
||||
$enabled_views = array();
|
||||
|
||||
$views = views_get_all_views();
|
||||
ksort($views);
|
||||
|
||||
foreach ($views as $view) {
|
||||
if (!isset($views[$view->name]->disabled) || !$views[$view->name]->disabled) {
|
||||
$enabled_views[$view->name] = check_plain($view->name);
|
||||
|
||||
// Provide more granular options for each page display
|
||||
$displays = array();
|
||||
foreach ($view->display as $id => $display) {
|
||||
if ($display->display_plugin == 'page') {
|
||||
$displays[$view->name .":". $id] = check_plain("-- {$display->display_title}");
|
||||
}
|
||||
}
|
||||
$enabled_views += $displays;
|
||||
}
|
||||
}
|
||||
return $enabled_views;
|
||||
}
|
||||
|
||||
function execute($view) {
|
||||
switch ($view->display_handler->display->display_plugin) {
|
||||
case 'page':
|
||||
case 'calendar':
|
||||
// Set contexts for this view.
|
||||
foreach ($this->get_contexts($view->name) as $context) {
|
||||
$this->condition_met($context, $view->name);
|
||||
}
|
||||
// Set any contexts associated with the current display
|
||||
if (!empty($view->current_display)) {
|
||||
foreach ($this->get_contexts("{$view->name}:{$view->current_display}") as $context) {
|
||||
$this->condition_met($context, "{$view->name}:{$view->current_display}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Base class for a context reaction.
|
||||
*/
|
||||
class context_reaction {
|
||||
var $plugin;
|
||||
var $title;
|
||||
var $description;
|
||||
|
||||
/**
|
||||
* Clone our references when we're being cloned.
|
||||
*
|
||||
* PHP 5.3 performs 'shallow' clones when clone()'ing objects, meaning that
|
||||
* any objects or arrays referenced by this object will not be copied, the
|
||||
* cloned object will just reference our objects/arrays instead. By iterating
|
||||
* over our properties and serializing and unserializing them, we force PHP to
|
||||
* copy them.
|
||||
*/
|
||||
function __clone() {
|
||||
foreach ($this as $key => $val) {
|
||||
if (is_object($val) || (is_array($val))) {
|
||||
$this->{$key} = unserialize(serialize($val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Do not override.
|
||||
*/
|
||||
function __construct($plugin, $info) {
|
||||
$this->plugin = $plugin;
|
||||
$this->title = isset($info['title']) ? $info['title'] : $plugin;
|
||||
$this->description = isset($info['description']) ? $info['description'] : '';
|
||||
}
|
||||
|
||||
function options_form($context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Options form submit handler.
|
||||
*/
|
||||
function options_form_submit($values) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings form. Provide variable settings for your reaction.
|
||||
*/
|
||||
function settings_form() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method that is called from hooks or other integration points with
|
||||
* Drupal. Note that it is not implemented in the base class, allowing
|
||||
* extending classes to change the function signature if necessary.
|
||||
*
|
||||
* function execute($value) {
|
||||
* foreach ($this->get_contexts($value) as $context) {
|
||||
* $this->condition_met($context, $value);
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieve active contexts that have values for this reaction.
|
||||
*/
|
||||
function get_contexts() {
|
||||
$contexts = array();
|
||||
foreach (context_active_contexts() as $context) {
|
||||
if ($this->fetch_from_context($context)) {
|
||||
$contexts[$context->name] = $context;
|
||||
}
|
||||
}
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve options from the context provided.
|
||||
*/
|
||||
function fetch_from_context($context) {
|
||||
return isset($context->reactions[$this->plugin]) ? $context->reactions[$this->plugin] : array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* Script placeholder markup.
|
||||
*/
|
||||
.script-placeholder {
|
||||
padding:100px 0px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Browser
|
||||
*/
|
||||
div.context-block-browser div.category { display:none; }
|
||||
|
||||
div.context-block-item,
|
||||
div.context-block-browser div.draggable-placeholder,
|
||||
#admin-toolbar div.context-block-browser div.context-block-item {
|
||||
font-size:11px;
|
||||
line-height:20px;
|
||||
height:20px;
|
||||
|
||||
text-shadow:#333 0px 1px 0px;
|
||||
color:#fff;
|
||||
|
||||
padding:5px 4px 4px 5px;
|
||||
margin:0px 1px 1px 0px;
|
||||
max-width:300px;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
|
||||
background:url(context_reaction_block.png) 0px -40px repeat-x;
|
||||
position:relative;
|
||||
|
||||
-moz-border-radius:5px;
|
||||
-webkit-border-radius:5px;
|
||||
-moz-user-select:none;
|
||||
-webkit-user-select:none;
|
||||
}
|
||||
|
||||
div.context-block-item span.icon {
|
||||
background:url(context_reaction_block.png) 0px -80px no-repeat;
|
||||
display:block;
|
||||
width:20px;
|
||||
height:20px;
|
||||
float:left;
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
div.context-block-loading { max-width:none; }
|
||||
|
||||
div.context-block-loading span.icon {
|
||||
background-position:-20px -80px;
|
||||
float:none;
|
||||
margin:0px auto;
|
||||
}
|
||||
|
||||
div.context-block-browser div.draggable-placeholder { padding:2px 1px 1px 2px; }
|
||||
|
||||
#admin-toolbar.horizontal div.context-block-browser div.draggable-placeholder,
|
||||
#admin-toolbar.horizontal div.context-block-browser div.context-block-item {
|
||||
width:180px;
|
||||
margin-right:1px;
|
||||
padding-right:9px;
|
||||
float:left;
|
||||
}
|
||||
|
||||
div.context-block-addable { cursor: move; }
|
||||
div.context-block-added { display:none !important; }
|
||||
|
||||
/**
|
||||
* Inline editing elements ============================================
|
||||
*/
|
||||
a.context-block-region { display:none; }
|
||||
a.context-block { display:none !important; }
|
||||
|
||||
body.context-editing div.context-block-region-empty a.context-block-region {
|
||||
-moz-border-radius:5px;
|
||||
-webkit-border-radius:5px;
|
||||
background:#666;
|
||||
color:#fff;
|
||||
opacity:.25;
|
||||
|
||||
display:block;
|
||||
height:40px;
|
||||
line-height:40px;
|
||||
|
||||
text-align:center;
|
||||
font-size:18px;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
body.context-editing .ui-sortable div.block { opacity:.25; }
|
||||
|
||||
body.context-editing .ui-sortable div.draggable {
|
||||
position:relative;
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
body.context-editing div.draggable-placeholder {
|
||||
-moz-border-radius:5px;
|
||||
-webkit-border-radius:5px;
|
||||
|
||||
background:#fff;
|
||||
border:3px dashed #666;
|
||||
opacity:.2;
|
||||
}
|
||||
|
||||
body.context-editing div.draggable:hover a.context-block-remove,
|
||||
body.context-editing div.draggable:hover a.context-block-handle {
|
||||
background:url(context_reaction_block.png) no-repeat;
|
||||
cursor:move;
|
||||
display:block;
|
||||
width:40px;
|
||||
height:40px;
|
||||
position:absolute;
|
||||
right:35px;
|
||||
top:-5px;
|
||||
z-index:100;
|
||||
}
|
||||
|
||||
body.context-editing div.draggable:hover a.context-block-remove {
|
||||
background-position:-40px 0px;
|
||||
cursor:pointer;
|
||||
right:-5px;
|
||||
}
|
||||
|
||||
div.context-block-hidden { display:none !important; }
|
||||
|
||||
div.block div.context-block-empty {
|
||||
text-align:center;
|
||||
padding:10px;
|
||||
opacity:.5;
|
||||
background:#fff;
|
||||
color:#666;
|
||||
}
|
||||
|
||||
/**
|
||||
* Block visibility ===================================================
|
||||
*/
|
||||
#context-blockform div.context-blockform-selector {
|
||||
height:20em;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
#context-blockform span.system-blocks { color:#999; }
|
||||
|
||||
#context-blockform td.blocks,
|
||||
#context-blockform td.selector {
|
||||
border:1px solid #ddd;
|
||||
padding:10px;
|
||||
width:50%;
|
||||
}
|
||||
|
||||
#context-blockform td.blocks div.label,
|
||||
#context-blockform td.blocks td,
|
||||
#context-blockform td.blocks th {
|
||||
background:#fff;
|
||||
padding:5px 5px 4px;
|
||||
border:0px;
|
||||
border-bottom:1px solid #ddd;
|
||||
}
|
||||
|
||||
#context-blockform td.blocks div.label { background:#eee; }
|
||||
#context-blockform td.blocks div.label a { float:right; }
|
||||
|
||||
#context-blockform td.blocks div.form-item,
|
||||
#context-blockform td.blocks input.block-weight { display:none; }
|
||||
|
||||
#context-ui-items #context-blockform {
|
||||
font-size:11px;
|
||||
line-height:15px;
|
||||
}
|
||||
|
||||
#context-ui-items #context-blockform div.form-checkboxes {
|
||||
height:auto;
|
||||
overflow:visible;
|
||||
padding:0px;
|
||||
margin:0px;
|
||||
border:0px;
|
||||
}
|
||||
|
||||
#context-ui-items #context-blockform div.form-item { padding:0px; }
|
||||
|
||||
#context-ui-items #context-blockform label {
|
||||
background:#eee;
|
||||
display:block;
|
||||
padding:5px;
|
||||
line-height:15px;
|
||||
}
|
||||
|
||||
#context-ui-items #context-blockform label.option {
|
||||
background:#fff;
|
||||
display:block;
|
||||
border:0px;
|
||||
}
|
|
@ -0,0 +1,593 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose blocks as context reactions.
|
||||
*/
|
||||
class context_reaction_block extends context_reaction {
|
||||
/**
|
||||
* Options form.
|
||||
*/
|
||||
function options_form($context) {
|
||||
// Rebuild the block info cache if necessary.
|
||||
$this->get_blocks(NULL, NULL, $this->rebuild_needed());
|
||||
$this->rebuild_needed(FALSE);
|
||||
|
||||
$theme_key = variable_get('theme_default', 'garland');
|
||||
$weight_delta = $this->max_block_weight();
|
||||
|
||||
$form = array(
|
||||
'#tree' => TRUE,
|
||||
'#theme' => 'context_block_form',
|
||||
'max_block_weight' => array(
|
||||
'#value' => $weight_delta,
|
||||
'#type' => 'value',
|
||||
),
|
||||
'state' => array(
|
||||
'#type' => 'hidden',
|
||||
'#attributes' => array('class' => 'context-blockform-state'),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Selector.
|
||||
*/
|
||||
$modules = module_list();
|
||||
$form['selector'] = array(
|
||||
'#type' => 'item',
|
||||
'#tree' => TRUE,
|
||||
'#prefix' => '<div class="context-blockform-selector">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
foreach ($this->get_blocks() as $block) {
|
||||
if (!isset($form['selector'][$block->module])) {
|
||||
$form['selector'][$block->module] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $modules[$block->module],
|
||||
'#options' => array(),
|
||||
);
|
||||
}
|
||||
$form['selector'][$block->module]['#options'][$block->bid] = check_plain($block->info);
|
||||
}
|
||||
ksort($form['selector']);
|
||||
|
||||
/**
|
||||
* Regions.
|
||||
*/
|
||||
$form['blocks'] = array(
|
||||
'#tree' => TRUE,
|
||||
'#theme' => 'context_block_regions_form',
|
||||
);
|
||||
foreach (system_region_list($theme_key) as $region => $label) {
|
||||
$form['blocks'][$region] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => $label,
|
||||
'#tree' => TRUE,
|
||||
);
|
||||
foreach ($this->get_blocks($region, $context) as $block) {
|
||||
if (!empty($block->context)) {
|
||||
$form['blocks'][$region][$block->bid] = array(
|
||||
'#value' => check_plain($block->info),
|
||||
'#weight' => $block->weight,
|
||||
'#type' => 'markup',
|
||||
'#tree' => TRUE,
|
||||
'weight' => array('#type' => 'weight', '#delta' => $weight_delta, '#default_value' => 0),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options form submit handler.
|
||||
*/
|
||||
function options_form_submit($values) {
|
||||
$blocks = array();
|
||||
$block_info = $this->get_blocks();
|
||||
|
||||
// Retrieve blocks from submitted JSON string.
|
||||
if (!empty($values['state'])) {
|
||||
$edited = $this->json_decode($values['state']);
|
||||
}
|
||||
else {
|
||||
$edited = array();
|
||||
}
|
||||
|
||||
foreach ($edited as $region => $bids) {
|
||||
foreach ($bids as $position => $bid) {
|
||||
if (isset($block_info[$bid])) {
|
||||
$blocks[$bid] = array(
|
||||
'module' => $block_info[$bid]->module,
|
||||
'delta' => $block_info[$bid]->delta,
|
||||
'region' => $region,
|
||||
'weight' => $position,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array('blocks' => $blocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Context editor form for blocks.
|
||||
*/
|
||||
function editor_form($context) {
|
||||
$form = array();
|
||||
if (module_exists('jquery_ui')) {
|
||||
jquery_ui_add(array('ui.draggable', 'ui.droppable', 'ui.sortable'));
|
||||
drupal_add_js(drupal_get_path('module', 'context_ui') .'/json2.js');
|
||||
drupal_add_js(drupal_get_path('module', 'context') .'/plugins/context_reaction_block.js');
|
||||
drupal_add_css(drupal_get_path('module', 'context') .'/plugins/context_reaction_block.css');
|
||||
|
||||
// We might be called multiple times so use a static to ensure this is set just once.
|
||||
static $once;
|
||||
if (!isset($once)) {
|
||||
$settings = array(
|
||||
'path' => url($_GET['q']),
|
||||
'params' => (object) array_diff_key($_GET, array('q' => '')),
|
||||
'scriptPlaceholder' => theme('context_block_script_placeholder', ''),
|
||||
);
|
||||
drupal_add_js(array('contextBlockEditor' => $settings), 'setting');
|
||||
$once = TRUE;
|
||||
}
|
||||
|
||||
$form['state'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#attributes' => array('class' => 'context-block-editor-state'),
|
||||
);
|
||||
$form['browser'] = array(
|
||||
'#type' => 'markup',
|
||||
'#value' => theme('context_block_browser', $this->get_blocks(NULL, NULL, $this->rebuild_needed()), $context),
|
||||
);
|
||||
$this->rebuild_needed(FALSE);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler context editor form.
|
||||
*/
|
||||
function editor_form_submit(&$context, $values) {
|
||||
$edited = !empty($values['state']) ? (array) $this->json_decode($values['state']) : array();
|
||||
|
||||
$options = array();
|
||||
|
||||
// Take the existing context values and remove blocks that belong affected regions.
|
||||
$affected_regions = array_keys($edited);
|
||||
if (!empty($context->reactions['block']['blocks'])) {
|
||||
$options = $context->reactions['block'];
|
||||
foreach ($options['blocks'] as $key => $block) {
|
||||
if (in_array($block['region'], $affected_regions)) {
|
||||
unset($options['blocks'][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through blocks and add in the ones that belong to the context.
|
||||
foreach ($edited as $region => $blocks) {
|
||||
foreach ($blocks as $weight => $block) {
|
||||
if ($block->context === $context->name) {
|
||||
$split = explode('-', $block->bid);
|
||||
$options['blocks'][$block->bid] = array(
|
||||
'module' => array_shift($split),
|
||||
'delta' => implode('-', $split),
|
||||
'region' => $region,
|
||||
'weight' => $weight,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings form for variables.
|
||||
*/
|
||||
function settings_form() {
|
||||
$form = array();
|
||||
$form['context_reaction_block_disable_core'] = array(
|
||||
'#title' => t('Core block system'),
|
||||
'#type' => 'select',
|
||||
'#options' => array(
|
||||
FALSE => t('Enabled'),
|
||||
TRUE => t('Disabled'),
|
||||
),
|
||||
'#default_value' => variable_get('context_reaction_block_disable_core', FALSE),
|
||||
'#description' => t('If enabled Context will include blocks enabled through the core block system when rendering regions. Disable to improve performance and hide the core block administration UI.')
|
||||
);
|
||||
$form['context_reaction_block_all_regions'] = array(
|
||||
'#title' => t('Show all regions'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => variable_get('context_reaction_block_all_regions', FALSE),
|
||||
'#description' => t('Show all regions including those that are empty. Enable if you are administering your site using the inline editor.')
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute.
|
||||
*/
|
||||
function execute($region) {
|
||||
// If the context_block querystring param is set, switch to AJAX rendering.
|
||||
// Note that we check the output buffer for any content to ensure that we
|
||||
// are not in the middle of a PHP template render.
|
||||
if (isset($_GET['context_block']) && !ob_get_contents()) {
|
||||
return $this->render_ajax($_GET['context_block']);
|
||||
}
|
||||
if ($this->is_enabled_region($region)) {
|
||||
return theme('context_block_editable_region', $region, $this->block_list($region), $this->is_editable());
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether inline editing requirements are met and that the current
|
||||
* user may edit.
|
||||
*/
|
||||
protected function is_editable($reset = FALSE) {
|
||||
// Check requirements.
|
||||
// Generally speaking, it does not make sense to allow anonymous users to
|
||||
// edit a context inline. Though it may be possible to save (and restore)
|
||||
// an edited context to an anonymous user's cookie or session, it's an
|
||||
// edge case and probably not something we want to encourage anyway.
|
||||
static $editable;
|
||||
if (!isset($editable) || $reset) {
|
||||
global $user;
|
||||
if (module_exists('jquery_ui') && $user->uid) {
|
||||
$editable = TRUE;
|
||||
jquery_ui_add(array('ui.draggable', 'ui.droppable', 'ui.sortable'));
|
||||
drupal_add_js(drupal_get_path('module', 'context') .'/plugins/context_reaction_block.js');
|
||||
drupal_add_css(drupal_get_path('module', 'context') .'/plugins/context_reaction_block.css');
|
||||
}
|
||||
else {
|
||||
$editable = FALSE;
|
||||
}
|
||||
}
|
||||
return $editable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of enabled regions for which blocks should be built.
|
||||
* Split out into a separate method for easy overrides in extending classes.
|
||||
*/
|
||||
protected function is_enabled_region($region) {
|
||||
global $theme;
|
||||
$regions = array_keys(system_region_list($theme));
|
||||
return in_array($region, $regions, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* An alternative version of block_list() that provides any context enabled blocks.
|
||||
*/
|
||||
function block_list($region) {
|
||||
static $build_queue;
|
||||
static $build_contexts;
|
||||
static $context_blocks = array();
|
||||
static $empty_blocks = array();
|
||||
|
||||
// Static cache a region => block array of blocks that should be built *if*
|
||||
// the given region is requested. Note that the blocks are not themselves
|
||||
// built in this first run as not all regions may be requested even if
|
||||
// active contexts include blocks in those regions.
|
||||
$contexts = context_active_contexts();
|
||||
if (!isset($build_queue) || $build_contexts != array_keys($contexts)) {
|
||||
$info = $this->get_blocks();
|
||||
$build_queue = array();
|
||||
$build_contexts = array_keys($contexts);
|
||||
foreach ($contexts as $context) {
|
||||
$options = $this->fetch_from_context($context);
|
||||
if (!empty($options['blocks'])) {
|
||||
foreach ($options['blocks'] as $block) {
|
||||
$block = (object) $block;
|
||||
$block->context = $context->name;
|
||||
$block->bid = "{$block->module}-{$block->delta}";
|
||||
$block->cache = isset($info[$block->bid]->cache) ? $info[$block->bid]->cache : BLOCK_NO_CACHE;
|
||||
$build_queue[$block->region][] = $block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Context blocks.
|
||||
if (!isset($context_blocks[$region])) {
|
||||
$context_blocks[$region] = array();
|
||||
$empty_blocks[$region] = array();
|
||||
if (!empty($build_queue[$region])) {
|
||||
foreach ($build_queue[$region] as $block) {
|
||||
$block = $this->build_block($block);
|
||||
if (!empty($block->content)) {
|
||||
$context_blocks[$region][] = $block;
|
||||
}
|
||||
else {
|
||||
$empty_blocks[$region][] = $block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get core blocks only if enabled.
|
||||
$blocks = !variable_get('context_reaction_block_disable_core', FALSE) ? block_list($region) : array();
|
||||
$blocks = array_merge($blocks, $context_blocks[$region]);
|
||||
|
||||
// Only include empty blocks if all regions should be shown or there are
|
||||
// non-empty blocks in the same region.
|
||||
$all_regions = variable_get('context_reaction_block_all_regions', FALSE);
|
||||
if ($this->is_editable() && ($all_regions || !empty($blocks))) {
|
||||
$blocks = array_merge($blocks, $empty_blocks[$region]);
|
||||
}
|
||||
|
||||
// Sort everything.
|
||||
uasort($blocks, array('context_reaction_block', 'block_sort'));
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a block's content. Largely taken from block_list().
|
||||
*/
|
||||
protected function build_block($block, $reset = FALSE) {
|
||||
// Block caching is not compatible with node_access modules. We also
|
||||
// preserve the submission of forms in blocks, by fetching from cache
|
||||
// only if the request method is 'GET'.
|
||||
static $cacheable;
|
||||
if (!isset($cacheable) || $reset) {
|
||||
$cacheable = !count(module_implements('node_grants')) && $_SERVER['REQUEST_METHOD'] == 'GET';
|
||||
}
|
||||
|
||||
if (!isset($block->content)) {
|
||||
$block->content = '';
|
||||
// Try fetching the block from cache.
|
||||
if ($cacheable && ($cid = _block_get_cache_id($block))) {
|
||||
if ($cache = cache_get($cid, 'cache_block')) {
|
||||
$array = $cache->data;
|
||||
}
|
||||
else {
|
||||
$array = module_invoke($block->module, 'block', 'view', $block->delta);
|
||||
cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
|
||||
}
|
||||
}
|
||||
// Otherwise build block.
|
||||
else {
|
||||
$array = module_invoke($block->module, 'block', 'view', $block->delta);
|
||||
}
|
||||
if (isset($array) && is_array($array)) {
|
||||
foreach ($array as $k => $v) {
|
||||
$block->$k = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($block->content)) {
|
||||
// Only query for custom block title if block core compatibility is enabled.
|
||||
if (!variable_get('context_reaction_block_disable_core', FALSE)) {
|
||||
global $user, $theme_key;
|
||||
$block->title = db_result(db_query("SELECT title FROM {blocks} WHERE module = '%s' AND delta = '%s' AND theme = '%s'", $block->module, $block->delta, $theme_key));
|
||||
}
|
||||
// Override default block title if a custom display title is present.
|
||||
if (!empty($block->title)) {
|
||||
// Check plain here to allow module generated titles to keep any markup.
|
||||
$block->subject = $block->title == '<none>' ? '' : check_plain($block->title);
|
||||
}
|
||||
if (!isset($block->subject)) {
|
||||
$block->subject = '';
|
||||
}
|
||||
}
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the safe weight range for a block being added to a region such that
|
||||
* there are enough potential unique weights to support all blocks.
|
||||
*/
|
||||
protected function max_block_weight() {
|
||||
$blocks = $this->get_blocks();
|
||||
$block_count = 0;
|
||||
foreach ($blocks as $region => $block_list) {
|
||||
$block_count += count($block_list);
|
||||
}
|
||||
// Add 2 to make sure there's space at either end of the block list
|
||||
return round(($block_count + 2) / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check or set whether a rebuild of the block info cache is needed.
|
||||
*/
|
||||
function rebuild_needed($set = NULL) {
|
||||
if (isset($set) && $set != variable_get('context_block_rebuild_needed', FALSE)) {
|
||||
variable_set('context_block_rebuild_needed', $set);
|
||||
}
|
||||
return (bool) variable_get('context_block_rebuild_needed', FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to generate a list of blocks from a specified region. If provided a context object,
|
||||
* will generate a full list of blocks for that region distinguishing between system blocks and
|
||||
* context-provided blocks.
|
||||
*
|
||||
* @param $region
|
||||
* The string identifier for a theme region. e.g. "left"
|
||||
* @param $context
|
||||
* A context object.
|
||||
*
|
||||
* @return
|
||||
* A keyed (by "module_delta" convention) array of blocks.
|
||||
*/
|
||||
function get_blocks($region = NULL, $context = NULL, $reset = FALSE) {
|
||||
static $block_info;
|
||||
|
||||
if (!isset($block_info) || $reset) {
|
||||
$block_info = array();
|
||||
if (!$reset) {
|
||||
$block_info = context_cache_get('block_info');
|
||||
}
|
||||
if (empty($block_info)) {
|
||||
$block_info = array();
|
||||
foreach (module_implements('block') as $module) {
|
||||
$module_blocks = module_invoke($module, 'block', 'list');
|
||||
if (!empty($module_blocks)) {
|
||||
foreach ($module_blocks as $delta => $block) {
|
||||
$block = (object) $block;
|
||||
$block->module = $module;
|
||||
$block->delta = $delta;
|
||||
$block->bid = "{$block->module}-{$block->delta}";
|
||||
$block_info[$block->bid] = $block;
|
||||
}
|
||||
}
|
||||
}
|
||||
context_cache_set('block_info', $block_info);
|
||||
}
|
||||
// Allow other modules that may declare blocks dynamically to alter
|
||||
// this list.
|
||||
drupal_alter('context_block_info', $block_info);
|
||||
|
||||
// Gather only region info from the database.
|
||||
$theme_key = variable_get('theme_default', 'garland');
|
||||
$result = db_query("SELECT module,weight,delta,region,status FROM {blocks} WHERE theme = '%s' ORDER BY weight ASC", $theme_key);
|
||||
while ($row = db_fetch_object($result)) {
|
||||
if ($row->status && isset($block_info["{$row->module}-{$row->delta}"])) {
|
||||
$block_info["{$row->module}-{$row->delta}"]->weight = $row->weight;
|
||||
$block_info["{$row->module}-{$row->delta}"]->region = $row->region;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$blocks = array();
|
||||
|
||||
// No region specified, provide all blocks.
|
||||
if (!isset($region)) {
|
||||
$blocks = $block_info;
|
||||
}
|
||||
// Region specified.
|
||||
else {
|
||||
foreach ($block_info as $bid => $block) {
|
||||
if (isset($block->region) && $block->region == $region) {
|
||||
$blocks[$bid] = $block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add context blocks if provided.
|
||||
if (is_object($context) && $options = $this->fetch_from_context($context)) {
|
||||
if (!empty($options['blocks'])) {
|
||||
foreach ($options['blocks'] as $block) {
|
||||
if (
|
||||
isset($block_info["{$block['module']}-{$block['delta']}"]) && // Block is valid.
|
||||
(!isset($region) || (!empty($region) && $block['region'] == $region)) // No region specified or regions match.
|
||||
) {
|
||||
$context_block = $block_info["{$block['module']}-{$block['delta']}"];
|
||||
$context_block->weight = $block['weight'];
|
||||
$context_block->region = $block['region'];
|
||||
$context_block->context = $context->name;
|
||||
$blocks[$context_block->bid] = $context_block;
|
||||
}
|
||||
}
|
||||
}
|
||||
uasort($blocks, array('context_reaction_block', 'block_sort'));
|
||||
}
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort callback.
|
||||
*/
|
||||
static function block_sort($a, $b) {
|
||||
return ($a->weight - $b->weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatibility wrapper around json_decode().
|
||||
*/
|
||||
protected function json_decode($json, $assoc = FALSE) {
|
||||
// Requires PHP 5.2.
|
||||
if (function_exists('json_decode')) {
|
||||
return json_decode($json, $assoc);
|
||||
}
|
||||
else {
|
||||
watchdog('context', 'Please upgrade your PHP version to one that supports json_decode.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Block renderer for AJAX requests. Triggered when $_GET['context_block']
|
||||
* is set. See ->execute() for how this is called.
|
||||
*/
|
||||
function render_ajax($param) {
|
||||
// Besure the page isn't a 404 or 403.
|
||||
$headers = drupal_set_header();
|
||||
|
||||
// Support for Pressflow drupal_set_header.
|
||||
if (!is_array($headers)) {
|
||||
$headers = explode("\n", $headers);
|
||||
}
|
||||
|
||||
foreach ($headers as $header) {
|
||||
if (strpos($header, "404 Not Found") !== FALSE || strpos($header, "403 Forbidden") !== FALSE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Set the header right away. This will inform any players in the stack
|
||||
// that we are in the middle of responding to an AJAX request.
|
||||
drupal_set_header('Content-Type: text/javascript; charset=utf-8');
|
||||
|
||||
if (strpos($param, ',') !== FALSE) {
|
||||
list($bid, $context) = explode(',', $param);
|
||||
list($module, $delta) = explode('-', $bid, 2);
|
||||
// Check token to make sure user has access to block.
|
||||
if (!(user_access('context ajax block access') || $this->context_block_ajax_rendering_allowed($bid))) {
|
||||
echo drupal_to_js(array('status' => 0));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Ensure $bid is valid.
|
||||
$info = $this->get_blocks();
|
||||
if (isset($info[$bid])) {
|
||||
$block = $info[$bid];
|
||||
$block->context = $context;
|
||||
$block->region = '';
|
||||
$block = $this->build_block($block);
|
||||
|
||||
if (empty($block->content)) {
|
||||
$block->content = "<div class='context-block-empty'>". t('This block appears empty when displayed on this page.') ."</div>";
|
||||
}
|
||||
|
||||
$css = array();
|
||||
|
||||
// On behalf of panels we try to load some css, but we don't support
|
||||
// panels inside panels currently.
|
||||
if ($block->module == 'panels_mini') {
|
||||
$panel = panels_mini_load($block->delta);
|
||||
$layout = panels_get_layout($panel->display->layout);
|
||||
if (!empty($layout['css'])) {
|
||||
if (file_exists(path_to_theme() . '/' . $layout['css'])) {
|
||||
$css[] = path_to_theme() . '/' . $layout['css'];
|
||||
}
|
||||
else {
|
||||
$css[] = $layout['path'] . '/' . $layout['css'];
|
||||
}
|
||||
}
|
||||
}
|
||||
echo drupal_to_js(array(
|
||||
'status' => 1,
|
||||
'block' => theme('context_block_editable_block', $block),
|
||||
'css' => $css,
|
||||
));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
echo drupal_to_js(array('status' => 0));
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow modules to selectively allow ajax rendering of a specific block
|
||||
*/
|
||||
private function context_block_ajax_rendering_allowed($bid) {
|
||||
$allowed = FALSE;
|
||||
foreach (module_invoke_all('context_allow_ajax_block_access', $bid) as $module_allow) {
|
||||
$allowed = $allow || $module_allow;
|
||||
if ($allowed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $allowed;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,414 @@
|
|||
|
||||
Drupal.behaviors.contextReactionBlock = function(context) {
|
||||
$('form.context-editor:not(.context-block-processed)')
|
||||
.addClass('context-block-processed')
|
||||
.each(function() {
|
||||
var id = $(this).attr('id');
|
||||
Drupal.contextBlockEditor = Drupal.contextBlockEditor || {};
|
||||
$(this).bind('init.pageEditor', function(event) {
|
||||
Drupal.contextBlockEditor[id] = new DrupalContextBlockEditor($(this));
|
||||
});
|
||||
$(this).bind('start.pageEditor', function(event, context) {
|
||||
// Fallback to first context if param is empty.
|
||||
if (!context) {
|
||||
context = $(this).data('defaultContext');
|
||||
}
|
||||
Drupal.contextBlockEditor[id].editStart($(this), context);
|
||||
});
|
||||
$(this).bind('end.pageEditor', function(event) {
|
||||
Drupal.contextBlockEditor[id].editFinish();
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
// Admin Form =======================================================
|
||||
//
|
||||
// ContextBlockForm: Init.
|
||||
$('#context-blockform:not(.processed)').each(function() {
|
||||
$(this).addClass('processed');
|
||||
Drupal.contextBlockForm = new DrupalContextBlockForm($(this));
|
||||
Drupal.contextBlockForm.setState();
|
||||
});
|
||||
|
||||
// ContextBlockForm: Attach block removal handlers.
|
||||
// Lives in behaviors as it may be required for attachment to new DOM elements.
|
||||
$('#context-blockform a.remove:not(.processed)').each(function() {
|
||||
$(this).addClass('processed');
|
||||
$(this).click(function() {
|
||||
$(this).parents('tr').eq(0).remove();
|
||||
Drupal.contextBlockForm.setState();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Context block form. Default form for editing context block reactions.
|
||||
*/
|
||||
DrupalContextBlockForm = function(blockForm) {
|
||||
this.state = {};
|
||||
|
||||
this.setState = function() {
|
||||
$('table.context-blockform-region', blockForm).each(function() {
|
||||
var region = $(this).attr('id').split('context-blockform-region-')[1];
|
||||
var blocks = [];
|
||||
$('tr', $(this)).each(function() {
|
||||
var bid = $(this).attr('id');
|
||||
blocks.push(bid);
|
||||
});
|
||||
Drupal.contextBlockForm.state[region] = blocks;
|
||||
});
|
||||
|
||||
// Serialize here and set form element value.
|
||||
$('form input.context-blockform-state').val(JSON.stringify(this.state));
|
||||
|
||||
// Hide enabled blocks from selector that are used
|
||||
$('table.context-blockform-region tr').each(function() {
|
||||
var bid = $(this).attr('id');
|
||||
$('div.context-blockform-selector input[value='+bid+']').parents('div.form-item').eq(0).hide();
|
||||
});
|
||||
// Show blocks in selector that are unused
|
||||
$('div.context-blockform-selector input').each(function() {
|
||||
var bid = $(this).val();
|
||||
if ($('table.context-blockform-region tr#'+bid).size() === 0) {
|
||||
$(this).parents('div.form-item').eq(0).show();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Tabledrag
|
||||
// Add additional handlers to update our blocks.
|
||||
$.each(Drupal.settings.tableDrag, function(base) {
|
||||
var table = $('#' + base + ':not(.processed)', blockForm);
|
||||
if (table && table.is('.context-blockform-region')) {
|
||||
table.addClass('processed');
|
||||
table.bind('mouseup', function(event) {
|
||||
Drupal.contextBlockForm.setState();
|
||||
return;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add blocks to a region
|
||||
$('td.blocks a', blockForm).each(function() {
|
||||
$(this).click(function() {
|
||||
var region = $(this).attr('href').split('#')[1];
|
||||
var selected = $("div.context-blockform-selector input:checked");
|
||||
if (selected.size() > 0) {
|
||||
selected.each(function() {
|
||||
// create new block markup
|
||||
var block = document.createElement('tr');
|
||||
var text = $(this).parents('div.form-item').eq(0).hide().children('label').text();
|
||||
$(block).attr('id', $(this).attr('value')).addClass('draggable');
|
||||
$(block).html("<td>"+ text + "<input class='block-weight' /></td><td><a href='' class='remove'>X</a></td>");
|
||||
|
||||
// add block item to region
|
||||
var base = "context-blockform-region-"+ region;
|
||||
Drupal.tableDrag[base].makeDraggable(block);
|
||||
$('table#'+base).append(block);
|
||||
Drupal.attachBehaviors($('table#'+base));
|
||||
|
||||
Drupal.contextBlockForm.setState();
|
||||
$(this).removeAttr('checked');
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Context block editor. AHAH editor for live block reaction editing.
|
||||
*/
|
||||
DrupalContextBlockEditor = function(editor) {
|
||||
this.editor = editor;
|
||||
this.state = {};
|
||||
this.blocks = {};
|
||||
this.regions = {};
|
||||
|
||||
// Category selector handler.
|
||||
// Also set to "Choose a category" option as browsers can retain
|
||||
// form values from previous page load.
|
||||
$('select.context-block-browser-categories', editor).change(function() {
|
||||
var category = $(this).val();
|
||||
var params = {
|
||||
containment: 'document',
|
||||
revert: true,
|
||||
dropOnEmpty: true,
|
||||
placeholder: 'draggable-placeholder',
|
||||
forcePlaceholderSize: true,
|
||||
helper: 'clone',
|
||||
appendTo: 'body',
|
||||
connectWith: ($.ui.version === '1.6') ? ['.ui-sortable'] : '.ui-sortable'
|
||||
};
|
||||
$('div.category', editor).hide().sortable('destroy');
|
||||
$('div.category-'+category, editor).show().sortable(params);
|
||||
});
|
||||
$('select.context-block-browser-categories', editor).val(0).change();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
DrupalContextBlockEditor.prototype.initBlocks = function(blocks) {
|
||||
var self = this;
|
||||
this.blocks = blocks;
|
||||
blocks.each(function() {
|
||||
$(this).addClass('draggable');
|
||||
$(this).prepend($('<a class="context-block-handle"></a>'));
|
||||
$(this).prepend($('<a class="context-block-remove"></a>').click(function() {
|
||||
$(this).parents('div.block').eq(0).fadeOut('medium', function() {
|
||||
$(this).remove();
|
||||
self.updateBlocks();
|
||||
});
|
||||
return false;
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
DrupalContextBlockEditor.prototype.initRegions = function(regions) {
|
||||
this.regions = regions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update UI to match the current block states.
|
||||
*/
|
||||
DrupalContextBlockEditor.prototype.updateBlocks = function() {
|
||||
var browser = $('div.context-block-browser');
|
||||
|
||||
// For all enabled blocks, mark corresponding addables as having been added.
|
||||
$('div.block, div.admin-block').each(function() {
|
||||
var bid = $(this).attr('id').split('block-')[1]; // Ugh.
|
||||
$('#context-block-addable-'+bid, browser).draggable('disable').addClass('context-block-added').removeClass('context-block-addable');
|
||||
});
|
||||
// For all hidden addables with no corresponding blocks, mark as addable.
|
||||
$('.context-block-item', browser).each(function() {
|
||||
var bid = $(this).attr('id').split('context-block-addable-')[1];
|
||||
if ($('#block-'+bid).size() === 0) {
|
||||
$(this).draggable('enable').removeClass('context-block-added').addClass('context-block-addable');
|
||||
}
|
||||
});
|
||||
|
||||
// Mark empty regions.
|
||||
$(this.regions).each(function() {
|
||||
if ($('div.block:not(.context-block-hidden):has(a.context-block)', this).size() > 0) {
|
||||
$(this).removeClass('context-block-region-empty');
|
||||
}
|
||||
else {
|
||||
$(this).addClass('context-block-region-empty');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Live update a region.
|
||||
*/
|
||||
DrupalContextBlockEditor.prototype.updateRegion = function(event, ui, region, op) {
|
||||
switch (op) {
|
||||
case 'over':
|
||||
$(region).removeClass('context-block-region-empty');
|
||||
break;
|
||||
case 'out':
|
||||
if (
|
||||
$('div.block:not(.context-block-hidden):has(a.context-block)', region).size() == 0 ||
|
||||
($('div.block:not(.context-block-hidden):has(a.context-block)', region).size() == 1 &&
|
||||
$('div.block:not(.context-block-hidden):has(a.context-block)', region).attr('id') == ui.item.attr('id'))
|
||||
) {
|
||||
$(region).addClass('context-block-region-empty');
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove script elements while dragging & dropping.
|
||||
*/
|
||||
DrupalContextBlockEditor.prototype.scriptFix = function(event, ui, editor, context) {
|
||||
if ($('script', ui.item)) {
|
||||
var placeholder = $(Drupal.settings.contextBlockEditor.scriptPlaceholder);
|
||||
var label = $('div.handle label', ui.item).text();
|
||||
placeholder.children('strong').html(label);
|
||||
$('script', ui.item).parent().empty().append(placeholder);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a block to a region through an AHAH load of the block contents.
|
||||
*/
|
||||
DrupalContextBlockEditor.prototype.addBlock = function(event, ui, editor, context) {
|
||||
var self = this;
|
||||
if (ui.item.is('.context-block-addable')) {
|
||||
var bid = ui.item.attr('id').split('context-block-addable-')[1];
|
||||
|
||||
// Construct query params for our AJAX block request.
|
||||
var params = Drupal.settings.contextBlockEditor.params;
|
||||
params.context_block = bid + ',' + context;
|
||||
|
||||
// Replace item with loading block.
|
||||
var blockLoading = $('<div class="context-block-item context-block-loading"><span class="icon"></span></div>');
|
||||
ui.item.addClass('context-block-added');
|
||||
ui.item.after(blockLoading);
|
||||
ui.sender.append(ui.item);
|
||||
|
||||
$.getJSON(Drupal.settings.contextBlockEditor.path, params, function(data) {
|
||||
if (data.status) {
|
||||
var newBlock = $(data.block);
|
||||
if ($('script', newBlock)) {
|
||||
$('script', newBlock).remove();
|
||||
}
|
||||
blockLoading.fadeOut(function() {
|
||||
$(this).replaceWith(newBlock);
|
||||
self.initBlocks(newBlock);
|
||||
self.updateBlocks();
|
||||
$.each(data.css, function(k, v){
|
||||
var cssfile = Drupal.settings.basePath + v;
|
||||
if ($('head link[href $='+cssfile+']').length === 0 ) {
|
||||
$('head').append('<link type="text/css" rel="stylesheet" media="all" href="' + cssfile + " />'");
|
||||
}
|
||||
});
|
||||
Drupal.attachBehaviors();
|
||||
});
|
||||
}
|
||||
else {
|
||||
blockLoading.fadeOut(function() { $(this).remove(); });
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (ui.item.is(':has(a.context-block)')) {
|
||||
self.updateBlocks();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update form hidden field with JSON representation of current block visibility states.
|
||||
*/
|
||||
DrupalContextBlockEditor.prototype.setState = function() {
|
||||
var self = this;
|
||||
|
||||
$(this.regions).each(function() {
|
||||
var region = $('a.context-block-region', this).attr('id').split('context-block-region-')[1];
|
||||
var blocks = [];
|
||||
$('a.context-block', $(this)).each(function() {
|
||||
if ($(this).attr('class').indexOf('edit-') != -1) {
|
||||
var bid = $(this).attr('id').split('context-block-')[1];
|
||||
var context = $(this).attr('class').split('edit-')[1].split(' ')[0];
|
||||
context = context ? context : 0;
|
||||
var block = {'bid': bid, 'context': context};
|
||||
blocks.push(block);
|
||||
}
|
||||
});
|
||||
self.state[region] = blocks;
|
||||
});
|
||||
|
||||
// Serialize here and set form element value.
|
||||
$('input.context-block-editor-state', this.editor).val(JSON.stringify(this.state));
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable text selection.
|
||||
*/
|
||||
DrupalContextBlockEditor.prototype.disableTextSelect = function() {
|
||||
if ($.browser.safari) {
|
||||
$('div.block:has(a.context-block):not(:has(input,textarea))').css('WebkitUserSelect','none');
|
||||
}
|
||||
else if ($.browser.mozilla) {
|
||||
$('div.block:has(a.context-block):not(:has(input,textarea))').css('MozUserSelect','none');
|
||||
}
|
||||
else if ($.browser.msie) {
|
||||
$('div.block:has(a.context-block):not(:has(input,textarea))').bind('selectstart.contextBlockEditor', function() { return false; });
|
||||
}
|
||||
else {
|
||||
$(this).bind('mousedown.contextBlockEditor', function() { return false; });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable text selection.
|
||||
*/
|
||||
DrupalContextBlockEditor.prototype.enableTextSelect = function() {
|
||||
if ($.browser.safari) {
|
||||
$('*').css('WebkitUserSelect','');
|
||||
}
|
||||
else if ($.browser.mozilla) {
|
||||
$('*').css('MozUserSelect','');
|
||||
}
|
||||
else if ($.browser.msie) {
|
||||
$('*').unbind('selectstart.contextBlockEditor');
|
||||
}
|
||||
else {
|
||||
$(this).unbind('mousedown.contextBlockEditor');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Start editing. Attach handlers, begin draggable/sortables.
|
||||
*/
|
||||
DrupalContextBlockEditor.prototype.editStart = function(editor, context) {
|
||||
var self = this;
|
||||
|
||||
// This is redundant to the start handler found in context_ui.js.
|
||||
// However it's necessary that we trigger this class addition before
|
||||
// we call .sortable() as the empty regions need to be visible.
|
||||
$(document.body).addClass('context-editing');
|
||||
this.editor.addClass('context-editing');
|
||||
|
||||
this.disableTextSelect();
|
||||
this.initBlocks($('div.block:has(a.context-block.edit-'+context+')'));
|
||||
this.initRegions($('a.context-block-region').parent());
|
||||
this.updateBlocks();
|
||||
|
||||
// First pass, enable sortables on all regions.
|
||||
$(this.regions).each(function() {
|
||||
var region = $(this);
|
||||
var params = {
|
||||
containment: 'document',
|
||||
revert: true,
|
||||
dropOnEmpty: true,
|
||||
placeholder: 'draggable-placeholder',
|
||||
forcePlaceholderSize: true,
|
||||
items: '> div.block:has(a.context-block.editable)',
|
||||
handle: 'a.context-block-handle',
|
||||
start: function(event, ui) { self.scriptFix(event, ui, editor, context); },
|
||||
stop: function(event, ui) { self.addBlock(event, ui, editor, context); },
|
||||
receive: function(event, ui) { self.addBlock(event, ui, editor, context); },
|
||||
over: function(event, ui) { self.updateRegion(event, ui, region, 'over'); },
|
||||
out: function(event, ui) { self.updateRegion(event, ui, region, 'out'); }
|
||||
};
|
||||
region.sortable(params);
|
||||
});
|
||||
|
||||
// Second pass, hook up all regions via connectWith to each other.
|
||||
$(this.regions).each(function() {
|
||||
$(this).sortable('option', 'connectWith', ['.ui-sortable']);
|
||||
});
|
||||
|
||||
// Terrible, terrible workaround for parentoffset issue in Safari.
|
||||
// The proper fix for this issue has been committed to jQuery UI, but was
|
||||
// not included in the 1.6 release. Therefore, we do a browser agent hack
|
||||
// to ensure that Safari users are covered by the offset fix found here:
|
||||
// http://dev.jqueryui.com/changeset/2073.
|
||||
if ($.ui.version === '1.6' && $.browser.safari) {
|
||||
$.browser.mozilla = true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Finish editing. Remove handlers.
|
||||
*/
|
||||
DrupalContextBlockEditor.prototype.editFinish = function() {
|
||||
this.editor.removeClass('context-editing');
|
||||
this.enableTextSelect();
|
||||
|
||||
// Remove UI elements.
|
||||
$(this.blocks).each(function() {
|
||||
$('a.context-block-handle, a.context-block-remove', this).remove();
|
||||
$(this).removeClass('draggable');
|
||||
});
|
||||
this.regions.sortable('destroy');
|
||||
|
||||
this.setState();
|
||||
|
||||
// Unhack the user agent.
|
||||
if ($.ui.version === '1.6' && $.browser.safari) {
|
||||
$.browser.mozilla = false;
|
||||
}
|
||||
};
|
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,256 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="80"
|
||||
height="120"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
version="1.0"
|
||||
sodipodi:docname="context_reaction_block.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
inkscape:export-filename="/home/devseed/kitrium/profiles/openatrium/modules/contrib/context/plugins/context_reaction_block.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3186">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0.1254902"
|
||||
offset="0"
|
||||
id="stop3188" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3190" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3191">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3193" />
|
||||
<stop
|
||||
style="stop-color:#c0c0c0;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3195" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective10" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3191"
|
||||
id="linearGradient3197"
|
||||
x1="10"
|
||||
y1="10"
|
||||
x2="10"
|
||||
y2="30"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3191"
|
||||
id="linearGradient3199"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="10"
|
||||
y1="10"
|
||||
x2="10"
|
||||
y2="30" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3191"
|
||||
id="linearGradient3176"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="18"
|
||||
y1="81"
|
||||
x2="18"
|
||||
y2="99" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3186"
|
||||
id="linearGradient3192"
|
||||
x1="2"
|
||||
y1="92.5"
|
||||
x2="10"
|
||||
y2="92.5"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3191"
|
||||
id="linearGradient3255"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="18"
|
||||
y1="81"
|
||||
x2="18"
|
||||
y2="99" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3191"
|
||||
id="linearGradient3260"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="18"
|
||||
y1="81"
|
||||
x2="18"
|
||||
y2="99" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3191"
|
||||
id="linearGradient3265"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="18"
|
||||
y1="81"
|
||||
x2="18"
|
||||
y2="99" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3191"
|
||||
id="linearGradient3276"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="18"
|
||||
y1="81"
|
||||
x2="18"
|
||||
y2="99" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3191"
|
||||
id="linearGradient3284"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="18"
|
||||
y1="81"
|
||||
x2="18"
|
||||
y2="99" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
gridtolerance="10000"
|
||||
guidetolerance="10"
|
||||
objecttolerance="10"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="31.144684"
|
||||
inkscape:cy="24.681366"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2383"
|
||||
visible="true"
|
||||
enabled="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccsccccccccccssccsccc"
|
||||
id="path3287"
|
||||
d="M 30,84.5 C 27.8265,84.5 25.87799,85.506572 24.59375,87.0625 L 24.59375,87.09375 L 26,88.5 C 26.912944,87.291403 28.369734,86.5 30,86.5 C 32.044638,86.5 33.787894,87.740652 34.5625,89.5 L 31.5,89.5 L 35.5,93.5 L 39.5,89.5 L 39,89.5 L 36.6875,89.5 C 35.825628,86.615704 33.164199,84.5 30,84.5 z M 24.5,89.5 L 20.5,93.5 L 23.3125,93.5 C 24.174372,96.384296 26.835801,98.5 30,98.5 C 32.1735,98.5 34.12201,97.493428 35.40625,95.9375 C 35.411546,95.931083 35.400976,95.912686 35.40625,95.90625 L 34,94.5 C 33.087056,95.708597 31.630266,96.5 30,96.5 C 27.955362,96.5 26.212106,95.259348 25.4375,93.5 L 28.5,93.5 L 24.5,89.5 z"
|
||||
style="opacity:1;fill:#000000;fill-opacity:0.50196078000000000;fill-rule:nonzero;stroke:none;stroke-width:1.25000000000000000;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;color:#000000" />
|
||||
<rect
|
||||
style="opacity:1;fill:#404040;fill-opacity:0.75294118;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect2385"
|
||||
width="80"
|
||||
height="40"
|
||||
x="0"
|
||||
y="0"
|
||||
rx="10"
|
||||
ry="10" />
|
||||
<path
|
||||
id="path3183"
|
||||
d="M 20,12.5 L 17,15.5 L 19,15.5 L 19,20.5 L 14,20.5 L 14,18.5 L 11,21.5 L 14,24.5 L 14,22.5 L 19,22.5 L 19,27.5 L 17,27.5 L 20,30.5 L 23,27.5 L 21,27.5 L 21,22.5 L 26,22.5 L 26,24.5 L 29,21.5 L 26,18.5 L 26,20.5 L 21,20.5 L 21,15.5 L 23,15.5 L 20,12.5 z"
|
||||
style="opacity:1;fill:#000000;fill-opacity:0.50196078;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
style="opacity:1;fill:url(#linearGradient3199);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 20,11 L 17,14 L 19,14 L 19,19 L 14,19 L 14,17 L 11,20 L 14,23 L 14,21 L 19,21 L 19,26 L 17,26 L 20,29 L 23,26 L 21,26 L 21,21 L 26,21 L 26,23 L 29,20 L 26,17 L 26,19 L 21,19 L 21,14 L 23,14 L 20,11 z"
|
||||
id="path3161" />
|
||||
<path
|
||||
id="path3185"
|
||||
d="M 55.5,15.21875 C 55.372191,15.21875 55.254184,15.245816 55.15625,15.34375 L 53.84375,16.65625 C 53.647881,16.852119 53.647881,17.147881 53.84375,17.34375 L 58,21.5 L 53.84375,25.65625 C 53.647883,25.852118 53.647881,26.147881 53.84375,26.34375 L 55.15625,27.65625 C 55.352118,27.852119 55.647881,27.852119 55.84375,27.65625 L 60,23.5 L 64.15625,27.65625 C 64.352119,27.852119 64.64788,27.852119 64.84375,27.65625 L 66.15625,26.34375 C 66.352119,26.147881 66.352117,25.852118 66.15625,25.65625 L 62,21.5 L 66.15625,17.34375 C 66.352119,17.147882 66.352119,16.852119 66.15625,16.65625 L 64.84375,15.34375 C 64.64788,15.147881 64.352119,15.147881 64.15625,15.34375 L 60,19.5 L 55.84375,15.34375 C 55.745816,15.245816 55.627809,15.21875 55.5,15.21875 z"
|
||||
style="opacity:1;fill:#000000;fill-opacity:0.50196078;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
style="opacity:1;fill:url(#linearGradient3197);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 55.5,13.71875 C 55.372191,13.71875 55.254184,13.745816 55.15625,13.84375 L 53.84375,15.15625 C 53.647881,15.352119 53.647881,15.647881 53.84375,15.84375 L 58,20 L 53.84375,24.15625 C 53.647883,24.352118 53.647881,24.647881 53.84375,24.84375 L 55.15625,26.15625 C 55.352118,26.352119 55.647881,26.352119 55.84375,26.15625 L 60,22 L 64.15625,26.15625 C 64.352119,26.352119 64.64788,26.352119 64.84375,26.15625 L 66.15625,24.84375 C 66.352119,24.647881 66.352117,24.352118 66.15625,24.15625 L 62,20 L 66.15625,15.84375 C 66.352119,15.647882 66.352119,15.352119 66.15625,15.15625 L 64.84375,13.84375 C 64.64788,13.647881 64.352119,13.647881 64.15625,13.84375 L 60,18 L 55.84375,13.84375 C 55.745816,13.745816 55.627809,13.71875 55.5,13.71875 z"
|
||||
id="rect3173" />
|
||||
<rect
|
||||
style="opacity:1;fill:#404040;fill-opacity:0.50196078;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3179"
|
||||
width="1"
|
||||
height="30"
|
||||
x="40"
|
||||
y="5"
|
||||
ry="0.5"
|
||||
rx="0.5" />
|
||||
<rect
|
||||
y="40"
|
||||
x="0"
|
||||
height="40"
|
||||
width="80"
|
||||
id="rect2391"
|
||||
style="opacity:1;fill:#404040;fill-opacity:0.75294118;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<g
|
||||
id="g3215">
|
||||
<rect
|
||||
style="opacity:1;fill:#000000;fill-opacity:0.50196078000000000;fill-rule:nonzero;stroke:none;stroke-width:1.25000000000000000;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;color:#000000"
|
||||
id="rect3200"
|
||||
width="14"
|
||||
height="14"
|
||||
x="3"
|
||||
y="84.5"
|
||||
rx="2"
|
||||
ry="2" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3176);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:0;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 5,83 L 15,83 C 16.108,83 17,83.892 17,85 L 17,95 C 17,96.108 16.108,97 15,97 L 5,97 C 3.892,97 3,96.108 3,95 L 3,85 C 3,83.892 3.892,83 5,83 z"
|
||||
id="rect3198" />
|
||||
<rect
|
||||
ry="0.5"
|
||||
rx="0.5"
|
||||
y="87"
|
||||
x="5"
|
||||
height="8"
|
||||
width="10"
|
||||
id="rect3206"
|
||||
style="opacity:1;fill:#000000;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:1.25000000000000000;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
id="rect3208"
|
||||
d="M 5.5 87 C 5.223 87 5 87.223 5 87.5 L 5 94 L 6 88 L 14 88 L 15 94 L 15 87.5 C 15 87.223 14.777 87 14.5 87 L 5.5 87 z "
|
||||
style="opacity:1;fill:#000000;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<path
|
||||
style="opacity:1;fill:url(#linearGradient3284);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000000000000000;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;color:#000000"
|
||||
d="M 30,83 C 27.8265,83 25.87799,84.006572 24.59375,85.5625 L 24.59375,85.59375 L 26,87 C 26.912944,85.791403 28.369734,85 30,85 C 32.044638,85 33.787894,86.240652 34.5625,88 L 31.5,88 L 35.5,92 L 39.5,88 L 39,88 L 36.6875,88 C 35.825628,85.115704 33.164199,83 30,83 z M 24.5,88 L 20.5,92 L 23.3125,92 C 24.174372,94.884296 26.835801,97 30,97 C 32.1735,97 34.12201,95.993428 35.40625,94.4375 C 35.411546,94.431083 35.400976,94.412686 35.40625,94.40625 L 34,93 C 33.087056,94.208597 31.630266,95 30,95 C 27.955362,95 26.212106,93.759348 25.4375,92 L 28.5,92 L 24.5,88 z"
|
||||
id="path3231"
|
||||
sodipodi:nodetypes="ccccsccccccccccssccsccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Set the breadcrumb using a context reaction.
|
||||
*/
|
||||
class context_reaction_breadcrumb extends context_reaction_menu {
|
||||
/**
|
||||
* Override of execute().
|
||||
*/
|
||||
function execute(&$vars = NULL) {
|
||||
if ($active_paths = $this->get_active_paths()) {
|
||||
$breadcrumb = array(l(t('Home'), '<front>', array('purl' =>array('disabled' => TRUE))));
|
||||
foreach ($active_paths as $path) {
|
||||
$result = db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE hidden = 0 AND link_path = '%s'", $path);
|
||||
while ($parents = db_fetch_array($result)) {
|
||||
$set = FALSE;
|
||||
foreach (array_filter($parents) as $plid) {
|
||||
$parent = menu_link_load($plid);
|
||||
if ($parent && $parent['access'] && empty($parent['hidden']) && !empty($parent['title'])) {
|
||||
$set = TRUE;
|
||||
$breadcrumb[] = l($parent['title'], $parent['href']);
|
||||
}
|
||||
}
|
||||
// Only set the breadcrumb if one or more links were added to the
|
||||
// trail. If not, continue iterating through possible menu links.
|
||||
if ($set) {
|
||||
drupal_set_breadcrumb($breadcrumb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
class context_reaction_css_injector extends context_reaction {
|
||||
|
||||
function options_form($context) {
|
||||
$list = array();
|
||||
foreach (_css_injector_load_rule() as $css_rule) {
|
||||
$list[$css_rule['crid']] = $css_rule['title'];
|
||||
}
|
||||
ksort($list);
|
||||
|
||||
return array(
|
||||
'#title' => $this->title,
|
||||
'#description' => $this->description,
|
||||
'#options' => $list,
|
||||
'#type' => 'checkboxes',
|
||||
'#default_value' => $this->fetch_from_context($context),
|
||||
);
|
||||
}
|
||||
|
||||
function execute() {
|
||||
$contexts = $this->get_contexts();
|
||||
foreach ($contexts as $context) {
|
||||
if (!empty($context->reactions[$this->plugin])) {
|
||||
foreach ($context->reactions[$this->plugin] as $crid) {
|
||||
if ($css_rule = _css_injector_load_rule($crid)) {
|
||||
drupal_add_css(file_create_path($css_rule['file_path']), 'module', $css_rule['media'], $css_rule['preprocess']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Output context debug information.
|
||||
*/
|
||||
class context_reaction_debug extends context_reaction {
|
||||
function options_form($context) {
|
||||
return array('debug' => array('#type' => 'value', '#value' => TRUE));
|
||||
}
|
||||
|
||||
function options_form_submit($values) {
|
||||
return array('debug' => 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a list of active contexts.
|
||||
*/
|
||||
function execute() {
|
||||
$contexts = context_active_contexts();
|
||||
foreach ($contexts as $context) {
|
||||
if (!empty($context->reactions['debug'])) {
|
||||
if (user_access('administer site configuration') && module_exists('context_ui')) {
|
||||
$name = l($context->name, "admin/build/context/list/{$context->name}", array('query' => 'destination=' . $_GET['q']));
|
||||
}
|
||||
else {
|
||||
$name = check_plain($context->name);
|
||||
}
|
||||
drupal_set_message(t("Active context: !name", array('!name' => $name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose menu items as context reactions.
|
||||
*/
|
||||
class context_reaction_menu extends context_reaction {
|
||||
/**
|
||||
* Provide a form element that allow the admin to chose a menu item.
|
||||
*/
|
||||
function options_form($context) {
|
||||
$menus = menu_parent_options(array_reverse(menu_get_menus()), NULL);
|
||||
$root_menus = array();
|
||||
foreach ($menus as $key => $name) {
|
||||
$id = explode(':', $key);
|
||||
if ($id[1] == '0') {
|
||||
$root_menus[$id[0]] = check_plain($name);
|
||||
}
|
||||
else {
|
||||
$link = menu_link_load($id[1]);
|
||||
$identifier = $link['link_path'];
|
||||
$root_menu = $root_menus[$id[0]];
|
||||
while (isset($menus[$root_menu][$identifier])) {
|
||||
$identifier .= "'";
|
||||
}
|
||||
$menus[$root_menu][$identifier] = $name;
|
||||
}
|
||||
unset($menus[$key]);
|
||||
}
|
||||
array_unshift($menus, "-- ". t('None') ." --");
|
||||
return array(
|
||||
'#title' => $this->title,
|
||||
'#description' => $this->description,
|
||||
'#options' => $menus,
|
||||
'#type' => 'select',
|
||||
'#default_value' => $this->fetch_from_context($context),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of options_form_submit().
|
||||
* Trim any identifier padding for non-unique path menu items.
|
||||
*/
|
||||
function options_form_submit($values) {
|
||||
return trim($values, "'");
|
||||
}
|
||||
|
||||
/**
|
||||
* If primary + secondary links are pointed at the same menu, provide
|
||||
* contextual trailing by default.
|
||||
*/
|
||||
function execute(&$vars = NULL) {
|
||||
if (variable_get('menu_primary_links_source', 'primary-links') == variable_get('menu_secondary_links_source', 'secondary-links')) {
|
||||
$vars['primary_links'] = theme_get_setting('toggle_primary_links') ? $this->menu_navigation_links(variable_get('menu_primary_links_source', 'primary-links')) : $vars['primary_links'];
|
||||
$vars['secondary_links'] = theme_get_setting('toggle_secondary_links') ? $this->menu_navigation_links(variable_get('menu_secondary_links_source', 'secondary-links'), 1) : $vars['secondary_links'];
|
||||
}
|
||||
|
||||
$vars['primary_links'] = $this->menu_set_active($vars['primary_links']);
|
||||
$vars['secondary_links'] = $this->menu_set_active($vars['secondary_links']);
|
||||
}
|
||||
|
||||
function get_active_paths() {
|
||||
$active_paths = array();
|
||||
foreach ($this->get_contexts() as $context) {
|
||||
if (isset($context->reactions[$this->plugin])) {
|
||||
$active_paths[] = $context->reactions[$this->plugin];
|
||||
}
|
||||
}
|
||||
return $active_paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through a provided links array for use with theme_links()
|
||||
* (e.g. from menu_primary_links()) and provides an active class for
|
||||
* any items that have a path that matches an active context.
|
||||
*
|
||||
* @param $links
|
||||
* An array of links.
|
||||
* @param $reset
|
||||
* A boolean flag for resetting the static cache.
|
||||
*
|
||||
* @return
|
||||
* A modified links array.
|
||||
*/
|
||||
function menu_set_active($links = array(), $reset = FALSE) {
|
||||
$new_links = array();
|
||||
if (!empty($links)) {
|
||||
$active_paths = $this->get_active_paths();
|
||||
|
||||
// Iterate through the provided links and build a new set of links
|
||||
// that includes active classes
|
||||
foreach ($links as $key => $link) {
|
||||
if (!empty($link['href']) && in_array($link['href'], $active_paths)) {
|
||||
if (isset($link['attributes']['class'])) {
|
||||
$link['attributes']['class'] .= ' active';
|
||||
}
|
||||
else {
|
||||
$link['attributes']['class'] = 'active';
|
||||
}
|
||||
|
||||
if (strpos(' active', $key) === FALSE) {
|
||||
$new_links[$key .' active'] = $link;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$new_links[$key] = $link;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $new_links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around menu_navigation_links() that gives themers the option of
|
||||
* building navigation links based on an active context trail.
|
||||
*/
|
||||
function menu_navigation_links($menu_name, $level = 0) {
|
||||
// Retrieve original path so we can repair it after our hack.
|
||||
$original_path = $_GET['q'];
|
||||
|
||||
// Retrieve the first active menu path found.
|
||||
if ($active_paths = $this->get_active_paths()) {
|
||||
$path = current($active_paths);
|
||||
if (menu_get_item($path)) {
|
||||
menu_set_active_item($path);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the links requested
|
||||
$links = menu_navigation_links($menu_name, $level);
|
||||
|
||||
// Repair and get out
|
||||
menu_set_active_item($original_path);
|
||||
return $links;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Expose themes as context reactions.
|
||||
*/
|
||||
class context_reaction_theme extends context_reaction {
|
||||
/**
|
||||
* Editor form.
|
||||
*/
|
||||
function editor_form($context) {
|
||||
$form = $this->options_form($context);
|
||||
|
||||
// Hide descriptions which take up too much space.
|
||||
unset($form['title']['#description']);
|
||||
unset($form['subtitle']['#description']);
|
||||
unset($form['class']['#description']);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for editor form.
|
||||
*/
|
||||
function editor_form_submit($context, $values) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow admins to provide a section title, section subtitle and section class.
|
||||
*/
|
||||
function options_form($context) {
|
||||
$values = $this->fetch_from_context($context);
|
||||
$form = array(
|
||||
'#tree' => TRUE,
|
||||
'#title' => t('Theme variables'),
|
||||
'title' => array(
|
||||
'#title' => t('Section title'),
|
||||
'#description' => t('Provides this text as a <strong>$section_title</strong> variable for display in page.tpl.php when this context is active.'),
|
||||
'#type' => 'textfield',
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => isset($values['title']) ? $values['title'] : '',
|
||||
),
|
||||
'subtitle' => array(
|
||||
'#title' => t('Section subtitle'),
|
||||
'#description' => t('Provides this text as a <strong>$section_subtitle</strong> variable for display in page.tpl.php when this context is active.'),
|
||||
'#type' => 'textfield',
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => isset($values['subtitle']) ? $values['subtitle'] : '',
|
||||
),
|
||||
'class' => array(
|
||||
'#title' => t('Section class'),
|
||||
'#description' => t('Provides this text as an additional body class (in <strong>$body_classes</strong> in page.tpl.php) when this section is active.'),
|
||||
'#type' => 'textfield',
|
||||
'#maxlength' => 64,
|
||||
'#default_value' => isset($values['class']) ? $values['class'] : '',
|
||||
),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set 'section_title', and 'section_subtitle' if not set and merge all
|
||||
* additional classes onto the 'body_classes'.
|
||||
*/
|
||||
function execute(&$vars) {
|
||||
$classes = array();
|
||||
foreach ($this->get_contexts() as $k => $v) {
|
||||
if (!empty($v->reactions[$this->plugin]['title']) && !isset($vars['section_title'])) {
|
||||
$vars['section_title'] = check_plain(t($v->reactions[$this->plugin]['title']));
|
||||
}
|
||||
if (!empty($v->reactions[$this->plugin]['subtitle']) && !isset($vars['section_subtitle'])) {
|
||||
$vars['section_subtitle'] = check_plain(t($v->reactions[$this->plugin]['subtitle']));
|
||||
}
|
||||
if (!empty($v->reactions[$this->plugin]['class'])) {
|
||||
$classes[$v->reactions[$this->plugin]['class']] = $v->reactions[$this->plugin]['class'];
|
||||
}
|
||||
}
|
||||
$vars['body_classes'] .= !empty($classes) ? ' '. check_plain(implode(' ', $classes)) : '';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,524 @@
|
|||
<?php
|
||||
|
||||
class ContextConditionUserTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: user'),
|
||||
'description' => t('Test user condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools');
|
||||
$this->user1 = $this->drupalCreateUser(array('access content', 'administer site configuration'));
|
||||
$this->user2 = $this->drupalCreateUser(array('access content'));
|
||||
|
||||
// Grab role from user1.
|
||||
$role = '';
|
||||
foreach ($this->user1->roles as $r) {
|
||||
if ($r !== 'authenticated user') {
|
||||
$role = $r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create test context.
|
||||
ctools_include('export');
|
||||
$this->context = ctools_export_new_object('context');
|
||||
$this->context->name = 'testcontext';
|
||||
$this->context->conditions = array('user' => array('values' => array($role)));
|
||||
$this->context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($this->context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
parent::tearDown();
|
||||
context_delete($this->context);
|
||||
$edit = array();
|
||||
user_delete($edit, $this->user1->uid);
|
||||
user_delete($edit, $this->user2->uid);
|
||||
}
|
||||
|
||||
function test() {
|
||||
// User 1 triggers the context.
|
||||
$this->drupalLogin($this->user1);
|
||||
$this->drupalGet('node');
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
// User 2 does not.
|
||||
$this->drupalLogin($this->user2);
|
||||
$this->drupalGet('node');
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionUserPageTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: user page'),
|
||||
'description' => t('Test user page condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools');
|
||||
$this->user1 = $this->drupalCreateUser(array('access user profiles', 'access content', 'administer site configuration'));
|
||||
$this->user2 = $this->drupalCreateUser(array('access user profiles', 'access content'));
|
||||
|
||||
// Create test context.
|
||||
ctools_include('export');
|
||||
$this->context = ctools_export_new_object('context');
|
||||
$this->context->name = 'testcontext';
|
||||
$this->context->conditions = array('user_page' => array('values' => array('view' => 'view'), 'options' => array('mode' => 'all')));
|
||||
$this->context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($this->context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
parent::tearDown();
|
||||
context_delete($this->context);
|
||||
$edit = array();
|
||||
user_delete($edit, $this->user1->uid);
|
||||
user_delete($edit, $this->user2->uid);
|
||||
}
|
||||
|
||||
function test() {
|
||||
// Viewing any user profile triggers context.
|
||||
$this->drupalLogin($this->user1);
|
||||
$this->drupalGet("user/{$this->user1->uid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
$this->drupalGet("user/{$this->user2->uid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
// User form does not.
|
||||
$this->drupalGet("user/{$this->user1->uid}/edit");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
// Test current user mode
|
||||
$this->context->conditions['user_page']['options']['mode'] = 'current';
|
||||
$saved = context_save($this->context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
$this->drupalGet("user/{$this->user1->uid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
$this->drupalGet("user/{$this->user2->uid}");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
// Test other user mode
|
||||
$this->context->conditions['user_page']['options']['mode'] = 'other';
|
||||
$saved = context_save($this->context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
$this->drupalGet("user/{$this->user1->uid}");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
$this->drupalGet("user/{$this->user2->uid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionNodeTaxonomyTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: taxonomy'),
|
||||
'description' => t('Test taxonomy condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools', 'taxonomy');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'create page content'));
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create test vocab.
|
||||
$this->vocab = array(
|
||||
'name' => 'Test',
|
||||
'description' => 'Test vocab.',
|
||||
'multiple' => 0,
|
||||
'tags' => 0,
|
||||
'nodes' => array('page' => TRUE),
|
||||
);
|
||||
taxonomy_save_vocabulary($this->vocab);
|
||||
|
||||
// Create test terms.
|
||||
$this->terms = array();
|
||||
$this->terms['apples'] = array('name' => 'apples', 'vid' => $this->vocab['vid']);
|
||||
$this->terms['oranges'] = array('name' => 'oranges', 'vid' => $this->vocab['vid']);
|
||||
taxonomy_save_term($this->terms['apples']);
|
||||
taxonomy_save_term($this->terms['oranges']);
|
||||
|
||||
// Create test context.
|
||||
ctools_include('export');
|
||||
$this->context = ctools_export_new_object('context');
|
||||
$this->context->name = 'testcontext';
|
||||
$this->context->conditions = array('node_taxonomy' => array('values' => array($this->terms['apples']['tid'])));
|
||||
$this->context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($this->context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
parent::tearDown();
|
||||
context_delete($this->context);
|
||||
taxonomy_del_vocabulary($this->vocab['vid']);
|
||||
taxonomy_del_term($this->terms['apples']['tid']);
|
||||
taxonomy_del_term($this->terms['oranges']['tid']);
|
||||
}
|
||||
|
||||
function test() {
|
||||
// Apples does trigger the context.
|
||||
$this->drupalPost('node/add/page', array('title' => 'Apples', "taxonomy[{$this->vocab['vid']}]" => $this->terms['apples']['tid']), 'Save');
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
// Oranges does not trigger the context.
|
||||
$this->drupalPost('node/add/page', array('title' => 'Oranges', "taxonomy[{$this->vocab['vid']}]" => $this->terms['oranges']['tid']), 'Save');
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionLanguageTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: language'),
|
||||
'description' => t('Test language condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools', 'locale');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer languages'));
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Set up Spanish as second language.
|
||||
$this->drupalPost('admin/settings/language/add', array('langcode' => 'es'), t('Add language'));
|
||||
$this->drupalPost('admin/settings/language/configure', array('language_negotiation' => 1), t('Save settings'));
|
||||
}
|
||||
|
||||
function test() {
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('language' => array('values' => array('es')));
|
||||
$context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet('node');
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet('es/node');
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionSitewideTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: sitewide'),
|
||||
'description' => t('Test sitewide condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('sitewide' => array('values' => array(1)));
|
||||
$context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet('node');
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionPathTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: path'),
|
||||
'description' => t('Test path condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools', 'path');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer nodes'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('path' => array('values' => array('admin', 'node/*')));
|
||||
$context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet('admin');
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$node = $this->drupalCreateNode();
|
||||
$this->drupalGet("node/{$node->nid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet('node');
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
|
||||
// @TODO: Test with path alias
|
||||
// @TODO: Test with language prefixes
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionContextTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: context'),
|
||||
'description' => t('Test context condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer nodes'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('path' => array('values' => array('admin')));
|
||||
$context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$subcontext = ctools_export_new_object('context');
|
||||
$subcontext->name = 'subcontext';
|
||||
$subcontext->conditions = array('context' => array('values' => array('testcontext')));
|
||||
$subcontext->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($subcontext);
|
||||
$this->assertTrue($saved, "Context 'subcontext' saved.");
|
||||
|
||||
$this->drupalGet('admin');
|
||||
$this->assertText('Active context: testcontext');
|
||||
$this->assertText('Active context: subcontext');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
|
||||
// @TODO: Test exclusion
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionNodeTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: node'),
|
||||
'description' => t('Test node condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools', 'blog');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer nodes'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('node' => array('values' => array('blog')));
|
||||
$context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet("node/add/blog");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node/add/page");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
$node = $this->drupalCreateNode(array('type' => 'blog'));
|
||||
$this->drupalGet("node/{$node->nid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$node = $this->drupalCreateNode(array('type' => 'page'));
|
||||
$this->drupalGet("node/{$node->nid}");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
$context->conditions['node']['options']['node_form'] = 1;
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet("node/add/blog");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node/add/page");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionMenuTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: menu'),
|
||||
'description' => t('Test menu condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer nodes'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('menu' => array('values' => array('node/add')));
|
||||
$context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet("node/add/blog");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node/add");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionBookTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: book'),
|
||||
'description' => t('Test book condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools', 'book', 'menu');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer nodes'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
$book = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => 'new')));
|
||||
$child = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => $book->nid)));
|
||||
$dummy = $this->drupalCreateNode(array('type' => 'book'));
|
||||
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('book' => array('values' => array(book_menu_name($book->book['bid']))));
|
||||
$context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet("node/{$book->nid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node/{$child->nid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node/{$dummy->nid}");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
}
|
||||
}
|
||||
|
||||
class ContextConditionBookroot extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Condition: bookroot'),
|
||||
'description' => t('Test bookroot condition.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools', 'book', 'menu');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer nodes'));
|
||||
$this->drupalLogin($admin_user);
|
||||
variable_set('book_allowed_types', array('book', 'page'));
|
||||
}
|
||||
|
||||
function test() {
|
||||
$book = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => 'new')));
|
||||
$child = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => $book->nid)));
|
||||
|
||||
$dummy = $this->drupalCreateNode(array('type' => 'page', 'book' => array('bid' => 'new')));
|
||||
$dummy_child = $this->drupalCreateNode(array('type' => 'page', 'book' => array('bid' => $dummy->nid)));
|
||||
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('bookroot' => array('values' => array('book')));
|
||||
$context->reactions = array('debug' => array('debug' => TRUE));
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet("node/{$book->nid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node/{$child->nid}");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node/{$dummy->nid}");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node/{$dummy_child->nid}");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
$this->drupalGet("node/{$book->nid}/edit");
|
||||
$this->assertNoText('Active context: testcontext');
|
||||
|
||||
$context->conditions['bookroot']['options']['node_form'] = 1;
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet("node/{$book->nid}/edit");
|
||||
$this->assertText('Active context: testcontext');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
|
||||
class ContextReactionBlockTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Reaction: block'),
|
||||
'description' => t('Test block reaction.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools');
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('sitewide' => array('values' => array(1)));
|
||||
$context->reactions = array('block' => array('blocks' => array(
|
||||
'user-3' => array(
|
||||
'module' => 'user',
|
||||
'delta' => 3,
|
||||
'region' => 'right',
|
||||
'weight' => 0,
|
||||
),
|
||||
)));
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
$this->drupalGet('node');
|
||||
$this->assertText('Who\'s online');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
|
||||
// @TODO:
|
||||
// - Implement & test title overrides (if we plan to support them).
|
||||
// - Implement & test core + context block visibility conditions
|
||||
}
|
||||
}
|
||||
|
||||
class ContextReactionBlockAjaxTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Reaction: block ajax'),
|
||||
'description' => t('Test block reaction ajax behavior.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools');
|
||||
$admin_user = $this->drupalCreateUser(array('context ajax block access'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
$this->drupalGet('node', array(
|
||||
'query' => array('context_block' => 'user-3,testcontext')
|
||||
));
|
||||
|
||||
$this->assertText('"status": 1');
|
||||
$this->assertText("Who\'s online");
|
||||
}
|
||||
}
|
||||
|
||||
class ContextReactionBlockAjaxAccessTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Reaction: block ajax access'),
|
||||
'description' => t('Test block reaction ajax access behavior.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'context_ui', 'ctools');
|
||||
}
|
||||
|
||||
function test() {
|
||||
$this->drupalGet('node', array(
|
||||
'query' => array('context_block' => 'user-3,testcontext')
|
||||
));
|
||||
|
||||
$this->assertText('"status": 0');
|
||||
}
|
||||
}
|
||||
|
||||
class ContextReactionMenuTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Reaction: menu'),
|
||||
'description' => t('Test menu reaction.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools');
|
||||
$admin_user = $this->drupalCreateUser(array('administer nodes', 'administer site configuration'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('sitewide' => array('values' => array(1)));
|
||||
$context->reactions = array('menu' => 'node/add');
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
variable_set('menu_primary_links_source', 'navigation');
|
||||
variable_set('theme_default', 'garland');
|
||||
$this->refreshVariables();
|
||||
|
||||
$output = $this->drupalGet('user');
|
||||
$url = url('node/add');
|
||||
$active = $this->xpath('//li[contains(@class, "active")]/a[@href="'. $url .'"]');
|
||||
$this->assertTrue(!empty($active), t('Active menu item found.'));
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
}
|
||||
}
|
||||
|
||||
class ContextReactionBreadcrumbTest extends DrupalWebTestCase {
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Reaction: breadcrumb'),
|
||||
'description' => t('Test breadcrumb reaction.'),
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('context', 'ctools');
|
||||
$admin_user = $this->drupalCreateUser(array('administer nodes', 'administer site configuration'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function test() {
|
||||
ctools_include('export');
|
||||
$context = ctools_export_new_object('context');
|
||||
$context->name = 'testcontext';
|
||||
$context->conditions = array('path' => array('values' => array('node')));
|
||||
$context->reactions = array('breadcrumb' => 'admin/build');
|
||||
$saved = context_save($context);
|
||||
$this->assertTrue($saved, "Context 'testcontext' saved.");
|
||||
|
||||
variable_set('theme_default', 'garland');
|
||||
$this->refreshVariables();
|
||||
|
||||
$output = $this->drupalGet('node');
|
||||
$this->assertText('Home › Administer › Site building');
|
||||
$output = $this->drupalGet('user');
|
||||
$this->assertNoText('Home › Administer › Site building');
|
||||
|
||||
// Cleanup
|
||||
context_delete($context);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
class ContextUnitTest extends DrupalWebTestCase {
|
||||
public function getInfo() {
|
||||
return array(
|
||||
'name' => t('API unit tests'),
|
||||
'description' => t('Sets all possible context types and checks for integrity.') ,
|
||||
'group' => t('Context'),
|
||||
);
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp('context');
|
||||
}
|
||||
|
||||
public function test() {
|
||||
// define possible data types
|
||||
$set_types = array(
|
||||
'bool' => TRUE,
|
||||
'int' => 1,
|
||||
'string' => 'lorem',
|
||||
'array' => array('lorem'),
|
||||
'object' => new stdClass(),
|
||||
);
|
||||
$id_types = array('int', 'string');
|
||||
|
||||
// NAMESPACE
|
||||
foreach ($set_types as $type => $val) {
|
||||
$set = context_set($val);
|
||||
// Test return value of context_set()
|
||||
if (in_array($type, $id_types)) {
|
||||
// test set integrity
|
||||
$this->assertIdentical(true, $set, 'Space set successful.');
|
||||
// test get integrity
|
||||
$this->assertIdentical(array(), context_get($val), 'Namespace get successful.');
|
||||
$this->assertIdentical(true, context_exists($val), 'Namespace exists successful.');
|
||||
}
|
||||
else {
|
||||
$this->assertIdentical(false, $set, 'Prohibited namespace not established.');
|
||||
}
|
||||
context_clear();
|
||||
}
|
||||
|
||||
// NAMESPACE+ATTRIBUTE
|
||||
foreach ($set_types as $type => $val) {
|
||||
foreach ($set_types as $type2 => $val2) {
|
||||
// test set integrity
|
||||
$set = context_set($val, $val2);
|
||||
if (in_array($type, $id_types)) {
|
||||
// test set integrity
|
||||
if ($type2 != 'bool') {
|
||||
$this->assertIdentical(true, $set, 'Namespace and attribute set successful.');
|
||||
}
|
||||
else {
|
||||
$this->assertIdentical(false, $set);
|
||||
}
|
||||
// test get + exists integrity
|
||||
if (in_array($type2, $id_types)) {
|
||||
$this->assertIdentical(true, (context_get($val, $val2) == $val2), 'Namespace and attribute get successful.');
|
||||
$this->assertIdentical(true, context_exists($val, $val2), 'Namespace and attribute exists.');
|
||||
}
|
||||
else if (in_array($type2, array('array', 'object'))) {
|
||||
$this->assertIdentical(true, (context_get($val) == $val2), 'Namespace and attribute get successful.');
|
||||
$this->assertIdentical(true, context_exists($val), 'Namespace and attribute exists.');
|
||||
}
|
||||
}
|
||||
}
|
||||
context_clear();
|
||||
}
|
||||
|
||||
// NAMESPACE+ATTRIBUTE+VALUE, o lord
|
||||
foreach ($set_types as $type => $val) {
|
||||
foreach ($set_types as $type2 => $val2) {
|
||||
foreach ($set_types as $type3 => $val3) {
|
||||
$set = context_set($val, $val2, $val3);
|
||||
if (in_array($type, $id_types)) {
|
||||
if (in_array($type2, $id_types)) {
|
||||
$this->assertIdentical(true, (context_get($val, $val2, $val3) == $val3), 'Namespace, attribute and value get successful.');
|
||||
$this->assertIdentical(true, context_exists($val, $val2, $val3), 'Namespace, attribute and value exists.');
|
||||
}
|
||||
}
|
||||
context_clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<div id='context-block-addable-<?php print $bid ?>' class='context-block-item context-block-addable clear-block'>
|
||||
<span class='icon'></span>
|
||||
<?php print $info ?>
|
||||
</div>
|
|
@ -0,0 +1,17 @@
|
|||
<div class='context-block-browser clear-block'>
|
||||
|
||||
<div class='categories'><?php print theme('select', $categories) ?></div>
|
||||
|
||||
<?php foreach ($blocks as $module => $module_blocks): ?>
|
||||
|
||||
<?php if (!empty($module_blocks)): ?>
|
||||
<div class='category category-<?php print $module ?> clear-block'>
|
||||
<?php foreach ($module_blocks as $block): ?>
|
||||
<?php print theme('context_block_browser_item', $block); ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,5 @@
|
|||
<?php if ($empty): ?>
|
||||
<div id='<?php print $block->bid ?>' class='block context-block-hidden'><?php print $block->content ?></div>
|
||||
<?php else: ?>
|
||||
<?php print theme('block', $block) ?>
|
||||
<?php endif; ?>
|
|
@ -0,0 +1,13 @@
|
|||
<?php if ($editable && (!empty($blocks) || $show_always)): ?>
|
||||
<a class='context-block-region' id='context-block-region-<?php print $region ?>'><?php print $region_description ?></a>
|
||||
<?php foreach ($blocks as $block): ?>
|
||||
<?php print theme('context_block_editable_block', $block); ?>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<?php /* When themes check to see if there is any content is the region any
|
||||
whitespace will make the them think it's got content. Consequently
|
||||
we don't nest this following code. */ ?>
|
||||
<?php foreach ($blocks as $block): ?>
|
||||
<?php print theme('block', $block); ?>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Block form.
|
||||
*/
|
||||
function theme_context_block_form($form) {
|
||||
$rows = array(array(
|
||||
array('data' => drupal_render($form['blocks']), 'class' => 'blocks'),
|
||||
array('data' => drupal_render($form['selector']) . drupal_render($form['block']['help']), 'class' => 'selector'),
|
||||
));
|
||||
$output = drupal_render($form);
|
||||
$output .= theme('table', array(), $rows, array('id' => 'context-blockform'));
|
||||
return $output;;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the AJAX enabled block administration portion of the context_ui admin form.
|
||||
*/
|
||||
function theme_context_block_regions_form($form) {
|
||||
// Add draggable weights
|
||||
drupal_add_js('misc/tableheader.js');
|
||||
drupal_add_js(drupal_get_path('module', 'context') .'/plugins/context_reaction_block.js');
|
||||
drupal_add_css(drupal_get_path('module', 'context') .'/plugins/context_reaction_block.css');
|
||||
|
||||
$output = '';
|
||||
|
||||
foreach (element_children($form) as $region) {
|
||||
$attr = array(
|
||||
'id' => "context-blockform-region-{$region}",
|
||||
'class' => "context-blockform-region",
|
||||
);
|
||||
drupal_add_tabledrag($attr['id'], 'order', 'sibling', 'block-weight', NULL, NULL, FALSE);
|
||||
$rows = array();
|
||||
foreach (element_children($form[$region]) as $id) {
|
||||
$form[$region][$id]['weight']['#attributes'] = array('class' => 'block-weight');
|
||||
$label = $form[$region][$id]['#value'];
|
||||
$remove = l('X', $_GET['q'], array('fragment' => 'remove', 'attributes' => array('class' => 'remove')));
|
||||
$rows[] = array(
|
||||
'data' => array($label . drupal_render($form[$region][$id]['weight']), $remove),
|
||||
'class' => 'draggable',
|
||||
'id' => $id,
|
||||
);
|
||||
}
|
||||
$output .= "<div class='label context-blockform-regionlabel-{$region}'>";
|
||||
$output .= l('+ '. t('Add'), $_GET['q'], array('fragment' => $region, 'attributes' => array('class' => 'add-block')));
|
||||
$output .= $form[$region]['#title'];
|
||||
$output .= "</div>";
|
||||
$output .= theme('table', array(), $rows, $attr);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use placeholder content for script tags that need to be replaced.
|
||||
*/
|
||||
function theme_context_block_script_placeholder($text = '') {
|
||||
$message = t('Please reload the page to view this block.');
|
||||
return "<div class='script-placeholder'><strong>{$text}</strong><div class='description'>{$message}</div></div>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('context_block_browser').
|
||||
*/
|
||||
function template_preprocess_context_block_browser(&$vars) {
|
||||
$categories = array(
|
||||
'#type' => 'select',
|
||||
'#options' => array(0 => '<'. t('Choose a category') .'>'),
|
||||
'#attributes' => array('class' => 'context-block-browser-categories'),
|
||||
'#value' => 0,
|
||||
'#size' => 1,
|
||||
'#id' => '',
|
||||
'#name' => '',
|
||||
'#parents' => array(''),
|
||||
'#multiple' => FALSE,
|
||||
'#required' => FALSE,
|
||||
);
|
||||
$blocks = array();
|
||||
// Group blocks by module.
|
||||
foreach ($vars['blocks'] as $block) {
|
||||
if (!isset($categories[$block->module])) {
|
||||
$info = context_get_info('module', $block->module);
|
||||
$categories['#options'][$block->module] = !empty($info['name']) ? $info['name'] : $block->module;
|
||||
}
|
||||
$blocks[$block->module][$block->bid] = $block; // Don't call theme('context_block_browser_item') to allow others to alter.
|
||||
}
|
||||
$vars['categories'] = $categories; // Don't call theme('select') here to allow further preprocesses to alter the element.
|
||||
$vars['blocks'] = $blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('context_block_browser_item').
|
||||
*/
|
||||
function template_preprocess_context_block_browser_item(&$vars) {
|
||||
$vars['bid'] = $vars['block']->bid;
|
||||
$vars['info'] = check_plain($vars['block']->info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('context_block_editable_region').
|
||||
*/
|
||||
function template_preprocess_context_block_editable_region(&$vars) {
|
||||
if (!empty($vars['editable'])) {
|
||||
// Show when empty?
|
||||
$vars['show_always'] = variable_get('context_reaction_block_all_regions', FALSE);
|
||||
|
||||
// Provide the user-friendly name of the region
|
||||
global $theme_key;
|
||||
$regions = system_region_list($theme_key);
|
||||
$vars['region_description'] = isset($regions[$vars['region']]) ? $regions[$vars['region']] : $vars['region'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('context_block_editable_block').
|
||||
*/
|
||||
function template_preprocess_context_block_editable_block(&$vars) {
|
||||
$vars['empty'] = empty($vars['block']->content);
|
||||
if (isset($vars['block']->context)) {
|
||||
$vars['block']->content .= "<a id='context-block-{$vars['block']->module}-{$vars['block']->delta}' class='context-block editable edit-{$vars['block']->context}'></a>";
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue