first import
This commit is contained in:
339
sites/all/modules/boxes/LICENSE.txt
Normal file
339
sites/all/modules/boxes/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
49
sites/all/modules/boxes/README.txt
Normal file
49
sites/all/modules/boxes/README.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
# Boxes
|
||||
|
||||
Boxes module is a reimplementation of the custom blocks (boxes) that the core
|
||||
block module provides. It is a proof of concept for what a re-worked block
|
||||
module could do.
|
||||
|
||||
The module assumes that custom blocks are configuration, and not content. This
|
||||
means that it is a reasonable action to ask for all blocks at one time, this is
|
||||
in fact exactly what the core block module does.
|
||||
|
||||
## Features
|
||||
|
||||
**Inline editing.** Boxes provides an inline interface for editing blocks,
|
||||
allowing you to change the contents of blocks without going to an admin page.
|
||||
|
||||
**Exportability.** Boxes provided blocks can be exported into code. Note; this
|
||||
includes the settings for the boxes themselves and not visibility rules. For
|
||||
exporting visibility settings the Context[1] module is recommended.
|
||||
|
||||
**Pluggable box types.** Boxes includes a basic "box type" that mimics how custom
|
||||
blocks behave in core. Boxes is designed to allow for modules to provide
|
||||
additional "box types" that have different configuration and rendering options.
|
||||
|
||||
## Chaos tools support
|
||||
|
||||
Boxes provides exportables for its blocks via the required Chaos tools[2]
|
||||
module. This allows modules to provide blocks in code that can be overwritten
|
||||
in the UI.
|
||||
|
||||
Chaos tools is required to use Boxes.
|
||||
|
||||
## Spaces support
|
||||
|
||||
Boxes provides a Spaces[3] controller class that allows individual spaces to
|
||||
override a particular block, or even define a completely new block for a
|
||||
specific space.
|
||||
|
||||
Spaces is not required by boxes.
|
||||
|
||||
## Todo
|
||||
|
||||
* Boxes need language awareness.
|
||||
* The inline editing experience could be nicer.
|
||||
|
||||
|
||||
[1] http://drupal.org/project/context
|
||||
[2] http://drupal.org/project/ctools
|
||||
[3] http://drupal.org/project/spaces
|
123
sites/all/modules/boxes/boxes.admin.inc
Normal file
123
sites/all/modules/boxes/boxes.admin.inc
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Generate form for creating new boxes.
|
||||
*/
|
||||
function boxes_add_form($form, $form_state, $plugin_key) {
|
||||
$form_state['box'] = boxes_factory($plugin_key);
|
||||
$form = boxes_box_form($form, $form_state);
|
||||
$form['delta'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Machine name'),
|
||||
'#description' => t('Lowercase letters, numbers and underscores only'),
|
||||
'#required' => TRUE,
|
||||
'#element_validate' => array('boxes_validate_delta'),
|
||||
'#size' => 32,
|
||||
'#maxlength' => 32,
|
||||
'#weight' => -20,
|
||||
);
|
||||
$form['submit']['#attributes']['class'] = array();
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate handler for box delta.
|
||||
*/
|
||||
function boxes_validate_delta($element, &$form_state) {
|
||||
if (!preg_match('!^[a-z0-9_]+$!', $element['#value'])) {
|
||||
form_error($element, t('The machine-readable name must contain only lowercase letters, numbers, and underscores.'));
|
||||
}
|
||||
if ((strpos($element['#value'], 'boxes_add__') === 0) || boxes_box_load($element['#value'])) {
|
||||
form_error($element, t('The machine-readable name is already taken.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for box_add_form.
|
||||
*/
|
||||
function boxes_add_form_submit($form, &$form_state) {
|
||||
$box = boxes_factory($form_state['values']['plugin_key'], $form_state['values']);
|
||||
$box->save();
|
||||
drupal_set_message(t('%name has been created.', array('%name' => $box->description)));
|
||||
$form_state['redirect'] = 'admin/structure/block';
|
||||
}
|
||||
|
||||
/**
|
||||
* Box deletion form.
|
||||
*/
|
||||
function boxes_delete_form($form, $form_state, $box) {
|
||||
$form['delta'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $box->delta,
|
||||
);
|
||||
if (($box->export_type & EXPORT_IN_DATABASE) && ($box->export_type & EXPORT_IN_CODE)) {
|
||||
return confirm_form($form, t('Are you sure you want to revert the block %name?', array('%name' => $box->title)), 'admin/structure/block', '', t('Revert'), t('Cancel'));
|
||||
}
|
||||
elseif (!($box->export_type & EXPORT_IN_CODE)) {
|
||||
return confirm_form($form, t('Are you sure you want to delete the block %name?', array('%name' => $box->title)), 'admin/structure/block', '', t('Delete'), t('Cancel'));
|
||||
}
|
||||
drupal_not_found();
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for boxes_delete_form
|
||||
*/
|
||||
function boxes_delete_form_submit($form, &$form_state) {
|
||||
boxes_box_load($form_state['values']['delta'])->delete();
|
||||
$form_state['redirect'] = 'admin/structure/block';
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function for the form.
|
||||
*/
|
||||
function theme_boxes_box($variables) {
|
||||
$block = $variables['block'];
|
||||
|
||||
$empty = '';
|
||||
|
||||
// Box is empty
|
||||
if ((empty($block['title']) || ($block['title'] == '<none>') ) && empty($block['content'])) {
|
||||
|
||||
// add a class to mark the box as empty
|
||||
$empty = ' box-empty';
|
||||
|
||||
// show something if the block is empty but the user has the permission to edit it
|
||||
if (boxes_access_edit()) {
|
||||
$block['content'] = t('This box appears empty when displayed on this page. This is simply placeholder text.');
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$output = "<div id='boxes-box-" . $block['delta'] . "' class='boxes-box" . (!empty($block['editing']) ? ' boxes-box-editing' : '') . $empty . "'>";
|
||||
$output .= '<div class="boxes-box-content">' . $block['content'] . '</div>';
|
||||
if (!empty($block['controls'])) {
|
||||
$output .= '<div class="boxes-box-controls">';
|
||||
$output .= $block['controls'];
|
||||
$output .= '</div>';
|
||||
}
|
||||
if (!empty($block['editing'])) {
|
||||
$output .= '<div class="box-editor">' . drupal_render($block['editing']) . '</div>';
|
||||
}
|
||||
$output .= '</div>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback for settings form.
|
||||
*/
|
||||
function boxes_settings($form, $form_state) {
|
||||
$form['boxes_edit_location'] = array(
|
||||
'#title' => t('Edit location'),
|
||||
'#type' => 'radios',
|
||||
'#options' => array(
|
||||
BOXES_EDIT_SEPARATE_PAGE => t('Separate page'),
|
||||
BOXES_EDIT_IN_PLACE => t('Edit in place'),
|
||||
),
|
||||
'#default_value' => variable_get('boxes_edit_location', BOXES_EDIT_IN_PLACE),
|
||||
'#description' => t('Boxes can either be edited directly where they are displayed, or on a separate page.')
|
||||
);
|
||||
return system_settings_form($form);
|
||||
}
|
31
sites/all/modules/boxes/boxes.css
Normal file
31
sites/all/modules/boxes/boxes.css
Normal file
@@ -0,0 +1,31 @@
|
||||
.script-placeholder {
|
||||
padding:100px 0px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
/* Default state */
|
||||
.boxes-box-controls .cancel { display:none; }
|
||||
|
||||
/* Editing state */
|
||||
.boxes-box-editing .boxes-box-controls .edit { display:none; }
|
||||
.boxes-box-editing .boxes-box-controls .cancel { display:block; }
|
||||
|
||||
.boxes-box-editing .swirly {
|
||||
background-image: url(swirly.gif);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.boxes-box-editor {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.box-empty .boxes-box-content {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
opacity:.5;
|
||||
filter: alpha(opacity=5); /* For IE8 and earlier */
|
||||
background:#fff;
|
||||
color: #666;
|
||||
}
|
19
sites/all/modules/boxes/boxes.info
Normal file
19
sites/all/modules/boxes/boxes.info
Normal file
@@ -0,0 +1,19 @@
|
||||
name = "Boxes"
|
||||
description = "Provides exports for custom blocks and spaces integration."
|
||||
core = 7.x
|
||||
dependencies[] = "ctools"
|
||||
dependencies[] = "block"
|
||||
|
||||
files[] = boxes.module
|
||||
files[] = boxes.admin.inc
|
||||
files[] = plugins/boxes_box.inc
|
||||
files[] = plugins/boxes_simple.inc
|
||||
files[] = plugins/spaces_controller_boxes.inc
|
||||
files[] = tests/boxes.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-01-24
|
||||
version = "7.x-1.1+0-dev"
|
||||
core = "7.x"
|
||||
project = "boxes"
|
||||
datestamp = "1358987992"
|
||||
|
200
sites/all/modules/boxes/boxes.install
Normal file
200
sites/all/modules/boxes/boxes.install
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the boxes module.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Implemenation of hook_schema().
|
||||
*/
|
||||
function boxes_schema() {
|
||||
$schema = array();
|
||||
$schema['box'] = array(
|
||||
'description' => 'Stores contents of custom-made blocks.',
|
||||
'fields' => array(
|
||||
'delta' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 32,
|
||||
'not null' => TRUE,
|
||||
'description' => "The block's {block}.delta.",
|
||||
),
|
||||
'plugin_key' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 64,
|
||||
'not null' => TRUE,
|
||||
'description' => "The plugin responsible for this block.",
|
||||
),
|
||||
'title' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 64,
|
||||
'not null' => TRUE,
|
||||
'description' => "Block title.",
|
||||
),
|
||||
'description' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'default' => '',
|
||||
'description' => 'Block description.',
|
||||
),
|
||||
'options' => array(
|
||||
'type' => 'text',
|
||||
'not null' => FALSE,
|
||||
'size' => 'big',
|
||||
'serialize' => TRUE,
|
||||
'description' => 'Block content configuration.',
|
||||
),
|
||||
),
|
||||
'primary key' => array('delta'),
|
||||
'export' => array(
|
||||
'key' => 'delta',
|
||||
'identifier' => 'box',
|
||||
'api' => array(
|
||||
'owner' => 'boxes',
|
||||
'api' => 'box',
|
||||
'minimum_version' => 1,
|
||||
'current_version' => 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function boxes_uninstall() {
|
||||
$result = db_query("SELECT bid FROM {block} WHERE module='boxes'");
|
||||
foreach ($result as $data) {
|
||||
db_query("DELETE FROM {block} WHERE bid = :bid", array(':bid' => $data->bid));
|
||||
}
|
||||
variable_del('boxes_edit_location');
|
||||
}
|
||||
|
||||
/**
|
||||
* Make boxes content pluggable, move body/format into a serialized options
|
||||
* array, add plugin key field.
|
||||
*/
|
||||
function boxes_update_6100() {
|
||||
$ret = array();
|
||||
$result = db_query("SELECT delta, body, format FROM {custom_block}");
|
||||
while ($box = db_fetch_object($result)) {
|
||||
$body = array(
|
||||
'body' => $box->body,
|
||||
'format' => $box->format,
|
||||
);
|
||||
$box->body = serialize($body);
|
||||
drupal_write_record('box', $box, 'delta');
|
||||
}
|
||||
$spec = array(
|
||||
'type' => 'text',
|
||||
'not null' => FALSE,
|
||||
'size' => 'big',
|
||||
'serialize' => TRUE,
|
||||
'description' => 'Block content configuration.',
|
||||
);
|
||||
db_change_field('box', 'body', 'options', $spec);
|
||||
db_drop_field('box', 'format');
|
||||
$spec = array(
|
||||
'type' => 'varchar',
|
||||
'length' => 64,
|
||||
'not null' => TRUE,
|
||||
'description' => "The plugin responsible for this block.",
|
||||
);
|
||||
db_add_field('box', 'plugin_key', $spec);
|
||||
// TODO Please review the conversion of this statement to the D7 database API syntax.
|
||||
/* db_query("UPDATE {custom_block} SET plugin_key = 'simple'") */
|
||||
db_update('custom_block')
|
||||
->fields(array(
|
||||
'plugin_key' => 'simple',
|
||||
))
|
||||
->execute();
|
||||
// hook_update_N() no longer returns a $ret array. Instead, return
|
||||
// nothing or a translated string indicating the update ran successfully.
|
||||
// See http://drupal.org/node/224333#update_sql.
|
||||
return t('TODO Add a descriptive string here to show in the UI.') /* $ret */;
|
||||
}
|
||||
|
||||
/**
|
||||
* If Spaces is installed update existing spaces overrides.
|
||||
*/
|
||||
function boxes_update_6101() {
|
||||
$ret = array();
|
||||
if (module_exists('spaces')) {
|
||||
$result = db_query("SELECT * FROM {spaces_overrides} WHERE object_type = :object_type", array(':object_type' => 'boxes'));
|
||||
while ($row = db_fetch_object($result)) {
|
||||
$v = unserialize($row->value);
|
||||
$v->plugin_key = 'simple';
|
||||
$v->options = array(
|
||||
'body' => $v->body,
|
||||
'format' => $v->format,
|
||||
);
|
||||
unset($v->body);
|
||||
unset($v->format);
|
||||
$row->value = (array) $v;
|
||||
drupal_write_record('spaces_overrides', $row, array('type', 'id', 'object_type', 'object_id'));
|
||||
}
|
||||
$ret[] = array(
|
||||
'success' => TRUE,
|
||||
'query' => 'Updated Spaces overrides',
|
||||
);
|
||||
}
|
||||
// hook_update_N() no longer returns a $ret array. Instead, return
|
||||
// nothing or a translated string indicating the update ran successfully.
|
||||
// See http://drupal.org/node/224333#update_sql.
|
||||
return t('TODO Add a descriptive string here to show in the UI.') /* $ret */;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the box.delta column definition match blocks.delta
|
||||
*/
|
||||
function boxes_update_6102() {
|
||||
$ret = array();
|
||||
$result = db_query('SELECT delta FROM {custom_block} WHERE CHAR_LENGTH(delta) > :CHAR_LENGTH(delta)', array(':CHAR_LENGTH(delta)' => 32))->fetchField();
|
||||
if (empty($result)) {
|
||||
db_drop_primary_key('box');
|
||||
$spec = array(
|
||||
'type' => 'varchar',
|
||||
'length' => 32,
|
||||
'not null' => TRUE,
|
||||
);
|
||||
$new_keys = array('primary key' => array('delta'));
|
||||
db_change_field('box', 'delta', 'delta', $spec, $new_keys);
|
||||
}
|
||||
else {
|
||||
$ret['#abort'] = array(
|
||||
'success' => FALSE,
|
||||
'query' => "Could not resize the `box.delta` field. Some entries are larger than 32 characters and must be manually truncated.",
|
||||
);
|
||||
}
|
||||
// hook_update_N() no longer returns a $ret array. Instead, return
|
||||
// nothing or a translated string indicating the update ran successfully.
|
||||
// See http://drupal.org/node/224333#update_sql.
|
||||
return t('TODO Add a descriptive string here to show in the UI.') /* $ret */;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that Spaces overrides are stored as an object, not an array.
|
||||
*/
|
||||
function boxes_update_6103() {
|
||||
$ret = array();
|
||||
if (module_exists('spaces')) {
|
||||
$result = db_query("SELECT * FROM {spaces_overrides} WHERE object_type = :object_type", array(':object_type' => 'boxes'));
|
||||
while ($row = db_fetch_object($result)) {
|
||||
$v = unserialize($row->value);
|
||||
$row->value = (object) $v;
|
||||
drupal_write_record('spaces_overrides', $row, array('type', 'id', 'object_type', 'object_id'));
|
||||
}
|
||||
$ret[] = array(
|
||||
'success' => TRUE,
|
||||
'query' => 'Updated Spaces overrides',
|
||||
);
|
||||
}
|
||||
// hook_update_N() no longer returns a $ret array. Instead, return
|
||||
// nothing or a translated string indicating the update ran successfully.
|
||||
// See http://drupal.org/node/224333#update_sql.
|
||||
return t('TODO Add a descriptive string here to show in the UI.') /* $ret */;
|
||||
}
|
||||
|
140
sites/all/modules/boxes/boxes.js
Normal file
140
sites/all/modules/boxes/boxes.js
Normal file
@@ -0,0 +1,140 @@
|
||||
(function ($) {
|
||||
//create ajax commands to be used from the drupal ajax api
|
||||
Drupal.ajax.prototype.commands['getBlock'] = function(ajax, response, status) {
|
||||
var box = $(this).parents('.boxes-box');
|
||||
data = response;
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: data.url,
|
||||
data: { 'boxes_delta': data.delta },
|
||||
global: true,
|
||||
success: function(response, status) {
|
||||
if($('#boxes-box-form').dialog('isOpen')){
|
||||
$('#boxes-box-form').dialog('close');
|
||||
}
|
||||
$('.hasPopup').removeClass('hasPopup');
|
||||
box.removeClass('boxes-box-editing').find('.box-editor').remove().end().find('.boxes-box-content').show();
|
||||
ajax.success(response, status);
|
||||
},
|
||||
error: Drupal.ajax.error,
|
||||
dataType: 'json'
|
||||
});
|
||||
};
|
||||
Drupal.ajax.prototype.commands['showBoxForm'] = function(ajax, response, status) {
|
||||
if(!$('#boxes-box-form').size() || !$('#boxes-box-form').dialog('isOpen')){
|
||||
Drupal.ajax.prototype.commands.insert(ajax, response, status);
|
||||
$(response.selector).addClass('hasPopup');
|
||||
$('#boxes-box-form')
|
||||
.dialog({
|
||||
modal : true,
|
||||
close: function(e){
|
||||
//handle someone closing the box without clicking any buttons
|
||||
if (Drupal.wysiwygDetach && $('.wysiwyg', this).val()) {
|
||||
var item = $('.wysiwyg', this)[0];
|
||||
var params = Drupal.settings.wysiwyg.triggers[item.id];
|
||||
Drupal.wysiwygDetach(this, params['format'+$(item).val()])
|
||||
}
|
||||
|
||||
$(response.selector).removeClass('hasPopup').html(Drupal.t('Loading...'));
|
||||
$('.boxes-ajax.use-ajax-submit.form-submit[value="Cancel"]').click();
|
||||
$(this).dialog('destroy').remove();
|
||||
},
|
||||
open: function(ui, event){
|
||||
$(this).siblings('.ui-dialog-titlebar').children('.ui-dialog-titlebar-close').click(function(e){
|
||||
$('.boxes-ajax.use-ajax-submit.form-submit[value="Cancel"]').click();
|
||||
});
|
||||
},
|
||||
width: Math.min($(window).width() * .75, 750),
|
||||
height: Math.min($(window).height() * .75, 750),
|
||||
title : Drupal.t('Edit Box')
|
||||
});
|
||||
} else {
|
||||
//change the selector to just update the current form - in place (in the popup)
|
||||
response.selector = '#boxes-box-form';
|
||||
Drupal.ajax.prototype.commands.insert(ajax, response, status);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Drupal.behaviors.boxes = {
|
||||
attach: function(context, settings) {
|
||||
$('div.boxes-box-controls a:not(.boxes-processed)')
|
||||
.addClass('boxes-processed')
|
||||
.click(function() {
|
||||
// If we are not using edit-in-place, bail.
|
||||
if (this.href.indexOf('/admin/structure/block/manage/boxes/') != -1) {
|
||||
return;
|
||||
}
|
||||
var box = $(this).parents('.boxes-box');
|
||||
if (box.is('.boxes-box-editing')) {
|
||||
box.removeClass('boxes-box-editing').find('.box-editor').remove().end().find('.boxes-box-content').show();
|
||||
}
|
||||
else {
|
||||
// Show editing form - the form itself gets loaded via ajax..
|
||||
box.find('.boxes-box-content').hide().end().addClass('boxes-box-editing').prepend('<div class="box-editor"><div class="swirly"></div></div>');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
Drupal.ajax.prototype.commands['preReplaceContextBlock'] = function(ajax, response, status) {
|
||||
data = response
|
||||
Drupal.settings.boxes = Drupal.settings.boxes || {};
|
||||
var e = $('#' + data.id + ' a.context-block:first').clone();
|
||||
Drupal.settings.boxes[data.id] = e;
|
||||
};
|
||||
|
||||
Drupal.ajax.prototype.commands['postReplaceContextBlock'] = function(ajax, response, status) {
|
||||
data = response
|
||||
$('#' + data.id).append(Drupal.settings.boxes[data.id]);
|
||||
$('form.context-editor.context-editing').each(function() {
|
||||
var id = $(this).attr('id');
|
||||
if (Drupal.contextBlockEditor[id]) {
|
||||
Drupal.contextBlockEditor[id].initBlocks($('#' + data.id));
|
||||
}
|
||||
});
|
||||
};
|
||||
//If we have a contextual link to configure the block lets get rid of that and move our edit link
|
||||
//to the contextual dropdown
|
||||
$('.boxes-box-controls', context).each(function () {
|
||||
// See if we are within a panel.
|
||||
if ($(this).parent().parent().hasClass("pane-content")) {
|
||||
$(this).hide();
|
||||
}
|
||||
if($(this).parents(".block").find(".block-configure").length > 0) {
|
||||
$(this).parents(".block").find(".block-configure").after($(this).find("li.edit"));
|
||||
$(this).parents(".block").find(".block-configure").detach();
|
||||
}
|
||||
});
|
||||
|
||||
// Submit box form if Enter is pressed
|
||||
$('#boxes-box-form input').keydown(function (e) {
|
||||
if (!e) {
|
||||
e = window.event;
|
||||
}
|
||||
// Enter
|
||||
if (e.keyCode == 13) {
|
||||
e.preventDefault();
|
||||
// Save is always the first button (see boxes.module)
|
||||
$('.boxes-ajax.use-ajax-submit.form-submit:first').click();
|
||||
}
|
||||
});
|
||||
|
||||
//apply the popup form to 'add boxes' also
|
||||
$('.boxes-box-editing .box-editor #boxes-box-form').not('.processed').addClass('processed').dialog({
|
||||
modal : true,
|
||||
close: function(e){
|
||||
//handle someone closing the box without clicking any buttons
|
||||
$(this).remove();
|
||||
},
|
||||
open: function(event, ui) {
|
||||
//hide the close button on add on the popup to prevent various annoying errors
|
||||
$(this).siblings('.ui-dialog-titlebar').children('.ui-dialog-titlebar-close').hide();
|
||||
},
|
||||
width: Math.min($(window).width() * .75, 750),
|
||||
height: Math.min($(window).height() * .75, 750),
|
||||
title : Drupal.t('Configure Box')
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
})(jQuery);
|
847
sites/all/modules/boxes/boxes.module
Normal file
847
sites/all/modules/boxes/boxes.module
Normal file
@@ -0,0 +1,847 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Edit locations.
|
||||
*/
|
||||
define('BOXES_EDIT_IN_PLACE', 1);
|
||||
define('BOXES_EDIT_SEPARATE_PAGE', 2);
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function boxes_menu() {
|
||||
$items = array();
|
||||
ctools_include('plugins');
|
||||
$plugins = ctools_get_plugins('boxes', 'plugins');
|
||||
foreach ($plugins as $key => $info) {
|
||||
if (isset($info['title'])) {
|
||||
$items['admin/structure/block/box-add/' . $key] = array(
|
||||
'title' => 'Add ' . strtolower($info['title']),
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('boxes_add_form', 4),
|
||||
'access arguments' => array('administer boxes'),
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
'file' => 'boxes.admin.inc',
|
||||
);
|
||||
}
|
||||
}
|
||||
$items['admin/structure/block/manage/boxes/%boxes_box/delete'] = array(
|
||||
'title' => 'Delete box',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('boxes_delete_form', 5),
|
||||
'access arguments' => array('administer boxes'),
|
||||
'type' => MENU_CALLBACK,
|
||||
'file' => 'boxes.admin.inc',
|
||||
);
|
||||
$items['admin/config/user-interface/boxes'] = array(
|
||||
'title' => 'Boxes',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('boxes_settings'),
|
||||
'access arguments' => array('administer boxes'),
|
||||
'file' => 'boxes.admin.inc',
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access check for whether current user is able to edit boxes.
|
||||
*/
|
||||
function boxes_access_edit() {
|
||||
return user_access('administer boxes') || user_access('edit boxes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Access check for whether current user should be able to administer boxes.
|
||||
*/
|
||||
function boxes_access_admin() {
|
||||
return user_access('administer boxes') || (module_exists('spaces') && spaces_access_admin());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_permission().
|
||||
*/
|
||||
function boxes_permission() {
|
||||
return array(
|
||||
'edit boxes' => array(
|
||||
'title' => t('Edit boxes'),
|
||||
'description' => t('Edit existing boxes'),
|
||||
),
|
||||
'administer boxes' => array(
|
||||
'title' => t('Administer boxes'),
|
||||
'description' => t('Administer boxes'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function boxes_theme($existing, $type, $theme, $path) {
|
||||
return array(
|
||||
'boxes_box' => array(
|
||||
'variables' => array('block' => NULL),
|
||||
'path' => drupal_get_path('module', 'boxes'),
|
||||
'file' => 'boxes.admin.inc',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_info().
|
||||
*/
|
||||
function boxes_block_info() {
|
||||
ctools_include('plugins');
|
||||
$plugins = ctools_get_plugins('boxes', 'plugins');
|
||||
|
||||
$boxes = boxes_box_load();
|
||||
$blocks = array();
|
||||
foreach ($boxes as $box) {
|
||||
$blocks[$box->delta]['info'] = $box->description;
|
||||
// Let context group the instances together
|
||||
$blocks[$box->delta]['context_group'] = t('Boxes for @plugin', array('@plugin' => $plugins[$box->plugin_key]['title']));
|
||||
// Let each box determine how it is cached
|
||||
$blocks[$box->delta]['cache'] = $box->cache_setting();
|
||||
}
|
||||
|
||||
// 'Add' blocks for editing a page inline
|
||||
foreach ($plugins as $key => $info) {
|
||||
if (isset($info['title'])) {
|
||||
$blocks["boxes_add__$key"]['info'] = t('Add custom @title', array('@title' => strtolower($info['title'])));
|
||||
$blocks["boxes_add__$key"]['cache'] = DRUPAL_CACHE_CUSTOM;
|
||||
}
|
||||
}
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_configure().
|
||||
*/
|
||||
function boxes_block_configure($delta) {
|
||||
if ($delta && strpos($delta, 'boxes_add__') !== 0) {
|
||||
if ($box = boxes_box_load($delta)) {
|
||||
$form_state = array('box' => $box);
|
||||
if ($box->options_form($form_state)) {
|
||||
$form = boxes_box_form(array(), $form_state);
|
||||
unset($form['submit']);
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_save().
|
||||
*/
|
||||
function boxes_block_save($delta, $edit) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_view().
|
||||
*/
|
||||
function boxes_block_view($delta) {
|
||||
// Add boxes JS.
|
||||
boxes_add_js();
|
||||
|
||||
ctools_include('export');
|
||||
|
||||
// If the 'add' box was requested, replace the delta with a unique delta.
|
||||
if (strpos($delta, 'boxes_add__') === 0) {
|
||||
$plugin_key = str_replace('boxes_add__', '', $delta);
|
||||
$identifier = (module_exists('spaces') && $space = spaces_get_space()) ? "{$space->type}-{$space->id}" : 'box';
|
||||
$hash = boxes_create_hash($identifier);
|
||||
$delta = $identifier . "-" . $hash;
|
||||
$box = boxes_factory($plugin_key, array('delta' => $delta));
|
||||
$form_state = array(
|
||||
'box' => $box,
|
||||
'plugin_key' => $plugin_key,
|
||||
'custom_action' => TRUE,
|
||||
'no_redirect' => TRUE,
|
||||
);
|
||||
|
||||
// We need to explicitly set the form input as empty to avoid the form being
|
||||
// processed. The actual form submission is handled in the footer.
|
||||
$form_state['input'] = array();
|
||||
$form_state['init_form'] = TRUE;
|
||||
$form = drupal_build_form('boxes_box_form', $form_state);
|
||||
|
||||
$block['delta'] = $delta;
|
||||
$block['content'] = '';
|
||||
$block['editing'] = $form;
|
||||
$block['content'] = theme('boxes_box', array('block' => $block));
|
||||
$plugin = ctools_get_plugins('boxes', 'plugins', $plugin_key);
|
||||
$block['subject'] = t('Add custom @title', array('@title' => strtolower($plugin['title'])));
|
||||
$block['boxes_plugin'] = $box->plugin_key;
|
||||
return $block;
|
||||
}
|
||||
elseif ($box = boxes_box_load($delta)) {
|
||||
// Generate content and provide an editing form if user has proper
|
||||
// permissions.
|
||||
$block = $box->render();
|
||||
if (boxes_access_edit()) {
|
||||
if (variable_get('boxes_edit_location', BOXES_EDIT_IN_PLACE) == BOXES_EDIT_IN_PLACE) {
|
||||
$edit_link = array(
|
||||
'title' => t('Edit Box'),
|
||||
'href' => $_GET['q'],
|
||||
'query' => array(
|
||||
'plugin_key' => $box->plugin_key,
|
||||
'boxes_delta' => $block['delta'],
|
||||
),
|
||||
'attributes' => array('class' => array('use-ajax')),
|
||||
);
|
||||
}
|
||||
else {
|
||||
$edit_link = array(
|
||||
'title' => t('Edit Box'),
|
||||
'href' => 'admin/structure/block/manage/boxes/' . $block['delta'] . '/configure',
|
||||
'query' => drupal_get_destination(),
|
||||
);
|
||||
|
||||
}
|
||||
$block['controls'] = theme('links', array(
|
||||
'links' => array(
|
||||
'edit' => $edit_link,
|
||||
'cancel' => array(
|
||||
'title' => t('Cancel'),
|
||||
'href' => $_GET['q'],
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
// Add additional_classes
|
||||
if (!empty($box->options['additional_classes'])) {
|
||||
$block['additional_classes'] = $box->options['additional_classes'];
|
||||
}
|
||||
$block['content'] = theme('boxes_box', array('block' => $block));
|
||||
$block['boxes_plugin'] = $box->plugin_key;
|
||||
return $block;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_page_alter().
|
||||
*/
|
||||
function boxes_page_alter(&$page) {
|
||||
$page['page_bottom']['boxes'] = array(
|
||||
'#markup' => boxes_footer(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_footer().
|
||||
*
|
||||
* All ajax requests are targeted back to the current page so that the proper
|
||||
* environment can be re-setup. Here in hook_footer we then detect that this is
|
||||
* an ajax submission and handle it.
|
||||
*/
|
||||
function boxes_footer() {
|
||||
|
||||
// if ckeditor is used, the base path needs to be set on the original
|
||||
// page load, or ckeditor will set it incorrectly to the root.
|
||||
// while this is loaded on every page it is just a single set of a variable.
|
||||
if (module_exists("wysiwyg") && ($editor = wysiwyg_get_editor('ckeditor'))) {
|
||||
$base = base_path();
|
||||
drupal_add_js("window.CKEDITOR_BASEPATH = '$base{$editor['library path']}/'", 'inline');
|
||||
}
|
||||
|
||||
// Besure the page isn't a 404 or 403.
|
||||
$headers = drupal_get_http_header();
|
||||
foreach ($headers as $header) {
|
||||
if ($header == "HTTP/1.1 404 Not Found" || $header == "HTTP/1.1 403 Forbidden") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!empty($_GET['boxes_delta']) && boxes_access_edit()) {
|
||||
include_once('includes/ajax.inc');
|
||||
$output = array();
|
||||
if (isset($_GET['plugin_key'])) {
|
||||
$plugin_key = $_GET['plugin_key'];
|
||||
$delta = $_GET['boxes_delta'];
|
||||
$box = boxes_box_load($delta);
|
||||
if (!$box && $plugin_key) {
|
||||
$box = boxes_factory($plugin_key, array('delta' => $delta));
|
||||
$form_state = array(
|
||||
'box' => $box,
|
||||
'plugin_key' => $plugin_key,
|
||||
'custom_action' => TRUE,
|
||||
'no_redirect' => TRUE,
|
||||
);
|
||||
}
|
||||
elseif (!$box) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
$form_state = array(
|
||||
'box' => $box,
|
||||
'no_redirect' => TRUE,
|
||||
);
|
||||
}
|
||||
$form = drupal_build_form('boxes_box_form', $form_state);
|
||||
$errors = form_set_error();
|
||||
|
||||
if (!empty($errors)) { /* validation error */
|
||||
$msg_and_form = theme('status_messages') . drupal_render($form);
|
||||
$output[] = array(
|
||||
'command' => 'showBoxForm',
|
||||
'method' => 'html',
|
||||
'selector' => '#block-boxes-' . $delta,
|
||||
'data' => $msg_and_form,
|
||||
'settings' => NULL,
|
||||
);
|
||||
}
|
||||
// if we are comming from a init form and need to continue then lets render the form again
|
||||
else if (empty($form_state['submitted']) || isset($_GET['init_form_continue'])) {
|
||||
$output[] = array(
|
||||
'command' => 'showBoxForm',
|
||||
'method' => 'html',
|
||||
'selector' => '#boxes-box-' . $delta,
|
||||
'data' => drupal_render($form),
|
||||
'settings' => NULL,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$output[] = array(
|
||||
'selector' => '#block-boxes-' . $delta,
|
||||
'command' => 'getBlock',
|
||||
'method' => 'replaceWith',
|
||||
'delta' => $delta,
|
||||
'url' => url($_GET['q'], array('absolute' => TRUE)),
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
$block = boxes_block_view($_GET['boxes_delta']);
|
||||
$block['module'] = 'boxes';
|
||||
$block['region'] = 'page_bottom';
|
||||
$block['content'] = array('#markup' => $block['content']);
|
||||
$block = (object) $block;
|
||||
|
||||
$renderable = _block_get_renderable_array(_block_render_blocks(array('boxes_' . $_GET['boxes_delta'] => $block)));
|
||||
$markup = trim(drupal_render($renderable));
|
||||
|
||||
$id = 'block-boxes-' . $_GET['boxes_delta'];
|
||||
// We cannot use drupal_html_id() here because it will increment the id on
|
||||
// pages where a box is already present. So we do its other transforms
|
||||
// manually.
|
||||
$id = strtr(drupal_strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
|
||||
$id = preg_replace('/[^A-Za-z0-9\-_]/', '', $id);
|
||||
$id = preg_replace('/\-+/', '-', $id);
|
||||
|
||||
|
||||
$output[] = ajax_command_replace('#' . $id, $markup);
|
||||
if (module_exists('context')) {
|
||||
array_unshift($output, array(
|
||||
'selector' => '#' . $id,
|
||||
'command' => 'preReplaceContextBlock',
|
||||
'id' => $id,
|
||||
));
|
||||
$output[] = array(
|
||||
'selector' => '#' . $id,
|
||||
'command' => 'postReplaceContextBlock',
|
||||
'id' => $id,
|
||||
);
|
||||
}
|
||||
}
|
||||
ajax_deliver(array('#type' => 'ajax', '#commands' => $output));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate box object.
|
||||
*
|
||||
* @param $plugin_key
|
||||
* The string id of the boxes plugin.
|
||||
* @param $values
|
||||
* The values to set on the box.
|
||||
*
|
||||
* @return a box object.
|
||||
*/
|
||||
function boxes_factory($plugin_key, $values = array()) {
|
||||
module_load_include('inc', 'boxes', 'plugins/boxes_box');
|
||||
return boxes_box::factory($plugin_key, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a box.
|
||||
*/
|
||||
function boxes_box_load($delta = NULL) {
|
||||
if (isset($delta)) {
|
||||
$box = boxes_box::load($delta);
|
||||
drupal_alter('boxes_box_load', $box, $delta);
|
||||
return $box;
|
||||
}
|
||||
ctools_include('export');
|
||||
$boxes = array();
|
||||
foreach (ctools_export_load_object('box') as $box) {
|
||||
$box = boxes_box::load($box->delta);
|
||||
if($box) {
|
||||
drupal_alter('boxes_box_load', $box, $delta);
|
||||
$boxes[$box->delta] = $box;
|
||||
}
|
||||
}
|
||||
return $boxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset boxes load caches.
|
||||
*/
|
||||
function boxes_box_load_reset() {
|
||||
boxes_box::reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Common element of the box form
|
||||
*/
|
||||
function boxes_box_form($form, &$form_state) {
|
||||
$box = $form_state['box'];
|
||||
if(method_exists($box, "box_form")) {
|
||||
return $box->box_form($form, $form_state);
|
||||
}
|
||||
// For hook_block_save()
|
||||
$form['plugin_key'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $box->plugin_key,
|
||||
);
|
||||
$form['delta'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $box->delta,
|
||||
);
|
||||
$form['description'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Box description'),
|
||||
'#default_value' => $box->description,
|
||||
'#maxlength' => 64,
|
||||
'#description' => t('A brief description of your box. Used for administrative purposes.'),
|
||||
'#required' => TRUE,
|
||||
'#weight' => -19,
|
||||
);
|
||||
$form['title'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Box title'),
|
||||
'#maxlength' => 64,
|
||||
'#description' => t('The rendered title of the box as shown to the user.'),
|
||||
'#default_value' => $box->title,
|
||||
'#weight' => -18,
|
||||
);
|
||||
$form['options'] = $box->options_form($form_state);
|
||||
$form['options']['#weight'] = -17;
|
||||
|
||||
$form['boxes_adv'] = array(
|
||||
'#type'=> 'fieldset',
|
||||
'#collapsed' => TRUE,
|
||||
'#collapsible' => TRUE,
|
||||
'#title' => t('Advanced Settings'),
|
||||
);
|
||||
$form['boxes_adv']['additional_classes'] = array(
|
||||
'#title' => t('Additional CSS classes'),
|
||||
'#description' => t('Optional CSS classes that will be added to the top-level div container for this box. Separate them with spaces.'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => isset($box->options['additional_classes']) ? $box->options['additional_classes'] : '',
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save'),
|
||||
'#attributes' => array('class' => array('boxes-ajax', 'use-ajax-submit')),
|
||||
);
|
||||
$form['cancel'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Cancel'),
|
||||
'#limit_validation_errors' => array(),
|
||||
'#attributes' => array('class' => array('boxes-ajax', 'use-ajax-submit')),
|
||||
);
|
||||
|
||||
if (!empty($form_state['custom_action'])) {
|
||||
$form['#action'] = url($_GET['q'], array('query' => array(
|
||||
'boxes_delta' => $box->delta,
|
||||
'plugin_key' => $form_state['plugin_key'],
|
||||
)));
|
||||
}
|
||||
if (isset($form_state['init_form']) && $box->use_multistep_create()) {
|
||||
unset($form['options']);
|
||||
unset($form['cancel']);
|
||||
$form['submit']['#value'] = t('Continue');
|
||||
if (!empty($form_state['custom_action'])) {
|
||||
$form['#action'] = url($_GET['q'], array(
|
||||
'query' => array(
|
||||
'boxes_delta' => $box->delta,
|
||||
'init_form_continue' => TRUE,
|
||||
'plugin_key' => $form_state['plugin_key'],
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_alter().
|
||||
*/
|
||||
function boxes_form_alter(&$form, &$form_state, $form_id) {
|
||||
$path = implode('/', array_slice(arg(), 0, 5));
|
||||
if (($form_id != 'block_admin_configure' || $path != 'admin/structure/block/manage/boxes') &&
|
||||
($form_id != 'boxes_add_form' || arg(3) != 'box-add')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the Box form submit handler and properly redirect to the correct admin page
|
||||
array_unshift($form['#submit'], 'boxes_box_form_submit');
|
||||
$form['#action'] = '?destination=admin/structure/block';
|
||||
|
||||
// Cancel behavior is different here
|
||||
unset($form['cancel']['#attributes']);
|
||||
$form['cancel']['#submit'] = array('boxes_block_cancel_submit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the inline form.
|
||||
*/
|
||||
function boxes_box_form_submit($form, $form_state) {
|
||||
if ($form_state['clicked_button']['#value'] == t('Cancel')) {
|
||||
return;
|
||||
}
|
||||
$box = boxes_factory($form_state['values']['plugin_key'], $form_state['values']);
|
||||
|
||||
// if options_submit is defined let the box process the submit
|
||||
if (method_exists($box, 'options_submit')) {
|
||||
$box->options_submit($form, $form_state);
|
||||
}
|
||||
// Let's set the additional_classes as an option
|
||||
$box->options['additional_classes'] = isset($form_state['values']['additional_classes']) ?
|
||||
$form_state['values']['additional_classes'] : array();
|
||||
|
||||
if (module_exists('spaces') && $space = spaces_get_space()) {
|
||||
$space->controllers->boxes->set($box->delta, $box);
|
||||
}
|
||||
else {
|
||||
$box->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_alter for block_admin_configure().
|
||||
*/
|
||||
function boxes_form_block_admin_configure_alter(&$form, &$form_state) {
|
||||
if ($form['module']['#value'] == 'boxes') {
|
||||
$box = boxes_box_load($form['delta']['#value']);
|
||||
if (($box->export_type & EXPORT_IN_DATABASE) && ($box->export_type & EXPORT_IN_CODE)) {
|
||||
$form['actions']['revert'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Revert'),
|
||||
'#submit' => array('boxes_block_delete_submit'),
|
||||
);
|
||||
}
|
||||
elseif (!($box->export_type & EXPORT_IN_CODE)) {
|
||||
$form['actions']['delete'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Delete'),
|
||||
'#submit' => array('boxes_block_delete_submit'),
|
||||
);
|
||||
}
|
||||
|
||||
// Cancel behavior is different on admin/structure page
|
||||
unset($form['settings']['cancel']);
|
||||
$form['actions']['cancel'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Cancel'),
|
||||
'#submit' => array('boxes_block_cancel_submit'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for box cancel from the block/manage/boxes/[MACHINE-NAME]/configure
|
||||
*/
|
||||
function boxes_block_cancel_submit($form, &$form_state) {
|
||||
if (module_exists('overlay')) {
|
||||
overlay_close_dialog();
|
||||
}
|
||||
else {
|
||||
drupal_goto('/admin/structure/block');
|
||||
}
|
||||
}
|
||||
|
||||
// Submit handler for box deletion.
|
||||
/**
|
||||
* @todo Please document this function.
|
||||
* @see http://drupal.org/node/1354
|
||||
*/
|
||||
function boxes_block_delete_submit($form, &$form_state) {
|
||||
// $form_state['redirect'] will not work here since we are using $form['#action'] with destination
|
||||
$_GET['destination'] = 'admin/structure/block/manage/boxes/' . $form_state['values']['delta'] . '/delete';
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters the block admin form to add delete links next to boxes blocks.
|
||||
*/
|
||||
function boxes_form_block_admin_display_form_alter(&$form, $form_state) {
|
||||
foreach (element_children($form['blocks']) as $i) {
|
||||
if (isset($form['blocks'][$i]['module']['#value']) && $form['blocks'][$i]['module']['#value'] == 'boxes') {
|
||||
$delta = $form['blocks'][$i]['delta']['#value'];
|
||||
if (strpos($delta, 'boxes_add__') !== 0) {
|
||||
$box = boxes_box_load($delta);
|
||||
if (($box->export_type & EXPORT_IN_DATABASE) && ($box->export_type & EXPORT_IN_CODE)) {
|
||||
$form['blocks'][$i]['delete'] = array(
|
||||
'#title' => t('revert'),
|
||||
'#type' => 'link',
|
||||
'#href' => 'admin/structure/block/manage/boxes/' . $delta . '/delete'
|
||||
);
|
||||
}
|
||||
elseif (!($box->export_type & EXPORT_IN_CODE)) {
|
||||
$form['blocks'][$i]['delete'] = array(
|
||||
'#title' => t('delete'),
|
||||
'#type' => 'link',
|
||||
'#href' => 'admin/structure/block/manage/boxes/' . $delta . '/delete'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ctools_plugin_api().
|
||||
*/
|
||||
function boxes_ctools_plugin_api($module, $api) {
|
||||
if ($module == 'spaces' && $api == 'plugins') {
|
||||
return array('version' => 3);
|
||||
}
|
||||
elseif ($module == 'boxes' && $api == 'plugins') {
|
||||
return array('version' => 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ctools_plugin_plugins().
|
||||
*/
|
||||
function boxes_ctools_plugin_type() {
|
||||
return array(
|
||||
'plugins' => array(
|
||||
'cache' => TRUE,
|
||||
'use hooks' => TRUE,
|
||||
'classes' => array('handler'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_boxes_plugins().
|
||||
*/
|
||||
function boxes_boxes_plugins() {
|
||||
$info = array();
|
||||
$path = drupal_get_path('module', 'boxes') . '/plugins';
|
||||
$info['box'] = array(
|
||||
'handler' => array(
|
||||
'class' => 'boxes_box',
|
||||
'file' => 'boxes_box.inc',
|
||||
'path' => $path,
|
||||
),
|
||||
);
|
||||
$info['simple'] = array(
|
||||
'title' => 'Box',
|
||||
'handler' => array(
|
||||
'parent' => 'box',
|
||||
'class' => 'boxes_simple',
|
||||
'file' => 'boxes_simple.inc',
|
||||
'path' => $path,
|
||||
),
|
||||
);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_spaces_plugins().
|
||||
*/
|
||||
function boxes_spaces_plugins() {
|
||||
$plugins = array();
|
||||
$plugins['spaces_controller_boxes'] = array(
|
||||
'handler' => array(
|
||||
'path' => drupal_get_path('module', 'boxes') . '/plugins',
|
||||
'file' => 'spaces_controller_boxes.inc',
|
||||
'class' => 'spaces_controller_boxes',
|
||||
'parent' => 'spaces_controler',
|
||||
),
|
||||
);
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_spaces_registry().
|
||||
*/
|
||||
function boxes_spaces_registry() {
|
||||
return array(
|
||||
'controllers' => array(
|
||||
'boxes' => array(
|
||||
'title' => t('Boxes'),
|
||||
'plugin' => 'spaces_controller_boxes',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_spaces_dashboard_block_access_alter().
|
||||
*
|
||||
* Provides access to blocks specific to each space.
|
||||
*/
|
||||
function boxes_spaces_dashboard_block_access_alter(&$access) {
|
||||
foreach (array_keys($access) as $bid) {
|
||||
list($module, $delta) = explode('-', $bid, 2);
|
||||
if ($module === 'boxes') {
|
||||
// This is the add block, give access to admins.
|
||||
if (strpos($delta, 'boxes_add__') === 0) {
|
||||
$access[$bid] = boxes_access_admin();
|
||||
}
|
||||
// If this box is specific to the current space, allow access.
|
||||
elseif (module_exists('spaces') && $space = spaces_get_space()) {
|
||||
$in_space = $space->controllers->boxes->get($delta, 'space');
|
||||
$access[$bid] = $access[$bid] || !empty($in_space);
|
||||
}
|
||||
// Outside of spaces, give admins access to all boxes.
|
||||
// @todo boxes_access_admin() may need to be boxes_access_edit().
|
||||
else {
|
||||
$access[$bid] = boxes_access_admin();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_context_block_info_alter().
|
||||
*
|
||||
* Provides spaces integration when working with blocks using context.
|
||||
*/
|
||||
function boxes_context_block_info_alter(&$blocks) {
|
||||
// Add boxes JS. If this is getting called, it's highly likely a context
|
||||
// inline editor is on the page.
|
||||
boxes_add_js();
|
||||
|
||||
if (module_exists('spaces') && $space = spaces_get_space()) {
|
||||
$item = menu_get_item();
|
||||
// Prevent space-specific blocks from appearing on the dashboard settings
|
||||
// page within a space.
|
||||
if (!(isset($item['page_callback'], $item['page_arguments'][0]) && $item['page_callback'] === 'drupal_get_form' && $item['page_arguments'][0] === 'spaces_dashboard_admin_form')) {
|
||||
foreach ($space->controllers->boxes->get() as $box) {
|
||||
$add = new stdClass();
|
||||
$add->bid = "boxes-{$box->delta}";
|
||||
$add->delta = $box->delta;
|
||||
$add->info = $box->description;
|
||||
$add->cache = DRUPAL_CACHE_CUSTOM;
|
||||
$add->module = 'boxes';
|
||||
$blocks[$add->bid] = $add;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_boxes_box_load_alter().
|
||||
*
|
||||
* Provides spaces integration for per-space overrides of a given box.
|
||||
*/
|
||||
function boxes_boxes_box_load_alter(&$box, $delta) {
|
||||
if (!$delta) {
|
||||
$delta = $box->delta;
|
||||
}
|
||||
if (module_exists('spaces') && $space = spaces_get_space()) {
|
||||
if ($space_box = $space->controllers->boxes->get($delta)) {
|
||||
// Some older overrides may be stored as an array, check for these and
|
||||
// convert them to objects.
|
||||
if (is_array($space_box)) {
|
||||
$space_box = (object) $space_box;
|
||||
}
|
||||
$box = boxes_factory($space_box->plugin_key, $space_box);
|
||||
$box->new = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_features_pipe_MODULE_alter().
|
||||
*/
|
||||
function boxes_features_pipe_block_alter(&$more, $data, $export) {
|
||||
foreach ($data as $bid) {
|
||||
$split = explode('-', $bid);
|
||||
$module = array_shift($split);
|
||||
$delta = implode('-', $split);
|
||||
|
||||
if ($module == 'boxes') {
|
||||
$more['box'][] = $delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add JavaScript to the page.
|
||||
*/
|
||||
function boxes_add_js() {
|
||||
static $added = FALSE;
|
||||
if ($added || (!boxes_access_admin() && !boxes_access_edit())) {
|
||||
return;
|
||||
}
|
||||
$added = TRUE;
|
||||
drupal_add_library('system', 'jquery.form', TRUE);
|
||||
drupal_add_library('system', 'drupal.form', TRUE);
|
||||
drupal_add_library('system', 'drupal.progress', TRUE);
|
||||
drupal_add_library('system', 'drupal.ajax', TRUE);
|
||||
drupal_add_library('system', 'ui.dialog');
|
||||
|
||||
drupal_add_js(drupal_get_path('module', 'boxes') . '/boxes.js');
|
||||
drupal_add_css(drupal_get_path('module', 'boxes') . '/boxes.css');
|
||||
drupal_add_js(array('getQ' => $_GET['q']), array('type' => 'setting', 'scope' => JS_DEFAULT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a hash for a block id.
|
||||
*/
|
||||
function boxes_create_hash($identifier) {
|
||||
global $user;
|
||||
$boxes = boxes_block_info();
|
||||
$hash = dechex(crc32($user->sid . microtime()));
|
||||
while (isset($boxes["{$identifier}-{$hash}"])) {
|
||||
$hash = dechex(crc32($user->sid . microtime()));
|
||||
}
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('block').
|
||||
*/
|
||||
function boxes_preprocess_block(&$vars) {
|
||||
$vars['classes_array'] = isset($vars['classes_array']) ? $vars['classes_array'] : array();
|
||||
if ($vars['block']->module === 'boxes') {
|
||||
}
|
||||
if ($vars['block']->module === 'boxes' && isset($vars['block']->boxes_plugin)) {
|
||||
$vars['classes_array'][] = 'block-boxes-' . $vars['block']->boxes_plugin;
|
||||
}
|
||||
if ($vars['block']->module === 'boxes' && isset($vars['block']->additional_classes)) {
|
||||
$vars['classes_array'] = array_merge($vars['classes_array'], explode(' ', $vars['block']->additional_classes));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocessor for theme('panels_pane').
|
||||
*/
|
||||
function boxes_preprocess_panels_pane(&$vars) {
|
||||
if ($vars['pane']->type == 'block') {
|
||||
list($module, $delta) = explode('-', $vars['pane']->subtype, 2);
|
||||
// Load up the actual box to check for additional classes.
|
||||
$box = boxes_box_load($delta);
|
||||
|
||||
if (isset($box->plugin_key)) {
|
||||
$vars['classes_array'][] = 'block-boxes-' . $box->plugin_key;
|
||||
}
|
||||
if (isset($box->options['additional_classes'])) {
|
||||
$vars['classes_array'] = array_merge($vars['classes_array'], explode(' ', $box->options['additional_classes']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ctools_block_info().
|
||||
*/
|
||||
function boxes_ctools_block_info($module, $delta, &$info) {
|
||||
$info['category'] = t('Boxes');
|
||||
}
|
||||
|
163
sites/all/modules/boxes/plugins/boxes_box.inc
Normal file
163
sites/all/modules/boxes/plugins/boxes_box.inc
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Abstract base class defining a box. A boxes content plugin provides a
|
||||
* form of options for configuring content and renders content for display.
|
||||
*
|
||||
* @see boxes_simple.
|
||||
*/
|
||||
abstract class boxes_box {
|
||||
static $boxes; // Static cache of box objects.
|
||||
public $delta;
|
||||
public $title;
|
||||
public $description;
|
||||
public $options;
|
||||
public $plugin_key;
|
||||
public $new;
|
||||
public $export_type;
|
||||
|
||||
/**
|
||||
* Load existing box by its unique identifier $delta.
|
||||
*/
|
||||
public static function load($delta, $reset = FALSE) {
|
||||
if (!isset(self::$boxes[$delta]) || $reset) {
|
||||
ctools_include('export');
|
||||
$box = ctools_export_load_object('box', 'names', array($delta));
|
||||
if (!empty($box) && $values = array_pop($box)) {
|
||||
self::$boxes[$delta] = self::factory($values->plugin_key, $values);
|
||||
self::$boxes[$delta]->new = FALSE;
|
||||
}
|
||||
}
|
||||
return isset(self::$boxes[$delta]) && get_class(self::$boxes[$delta]) != 'stdClass' ? self::$boxes[$delta] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate, populate and return a box object.
|
||||
*
|
||||
* @param $plugin_key
|
||||
*
|
||||
* @param $values
|
||||
* An array with at least a plugin_key key identifying the plugin class to
|
||||
* use for instantiating this box.
|
||||
*/
|
||||
public static function factory($plugin_key, $values) {
|
||||
ctools_include('plugins');
|
||||
if ($class = ctools_plugin_load_class('boxes', 'plugins', $plugin_key, 'handler')) {
|
||||
|
||||
// While we actually prefer to get objects, we need to allow for either,
|
||||
// so we convert it all to arrays.
|
||||
if (is_object($values)) {
|
||||
$values = (array) $values;
|
||||
}
|
||||
|
||||
$box = new $class();
|
||||
$box->plugin_key = $plugin_key;
|
||||
|
||||
foreach ($box as $key => $value) {
|
||||
if (isset($values[$key])) {
|
||||
$box->$key = $values[$key];
|
||||
}
|
||||
}
|
||||
foreach ($box->options_defaults() as $key => $value) {
|
||||
if (isset($values[$key])) {
|
||||
$box->options[$key] = $values[$key];
|
||||
}
|
||||
}
|
||||
return $box;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new box.
|
||||
*/
|
||||
protected function __construct() {
|
||||
$this->new = TRUE; // A box is new unless it exists in the DB or in code.
|
||||
$this->options = $this->options_defaults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the boxes cache.
|
||||
*
|
||||
* Both ctools and boxes current maintain caches, ctools of the config and
|
||||
* boxes of the loaded box objects. We clear them both.
|
||||
*/
|
||||
public static function reset() {
|
||||
ctools_include('export');
|
||||
ctools_export_load_object_reset('box');
|
||||
self::$boxes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a box.
|
||||
*/
|
||||
public function save() {
|
||||
if (empty($this->delta)) {
|
||||
throw new Exception(t('Cannot save box without a specified delta.'));
|
||||
}
|
||||
self::reset();
|
||||
$existing = boxes_box_load($this->delta);
|
||||
if ($existing && ($existing->export_type & EXPORT_IN_DATABASE)) {
|
||||
drupal_write_record('box', $this, array('delta'));
|
||||
}
|
||||
else {
|
||||
drupal_write_record('box', $this);
|
||||
}
|
||||
$this->new = FALSE;
|
||||
self::reset();
|
||||
module_exists('context') ? context_invalidate_cache() : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a box.
|
||||
*/
|
||||
public function delete() {
|
||||
self::reset();
|
||||
unset(self::$boxes[$this->delta]);
|
||||
db_delete('box')
|
||||
->condition('delta', $this->delta)
|
||||
->execute();
|
||||
module_exists('context') ? context_invalidate_cache() : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare if the box should use a multistep form for the create form.
|
||||
*
|
||||
* This might me necessary for forms that use ajax on the options form.
|
||||
* Currently Context does not load this block correctly and the ajax in the
|
||||
* form will not work. Methinks Context UI Editor needs to be upgraded to
|
||||
* D7 AJAX framework for this to not be required. That said the functionality
|
||||
* is potentially useful even with proper functioning AJAX.
|
||||
*/
|
||||
public function use_multistep_create() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block cache settings for this box. Subclasses can override this
|
||||
* to perform more intricate operations around deciding the cache settings of
|
||||
* the specific box instance.
|
||||
*/
|
||||
public function cache_setting() {
|
||||
return DRUPAL_CACHE_CUSTOM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare default options.
|
||||
*/
|
||||
abstract public function options_defaults();
|
||||
|
||||
/**
|
||||
* Provide options to configure content.
|
||||
*/
|
||||
abstract public function options_form(&$form_state);
|
||||
|
||||
/**
|
||||
* Render a block. Must return an array with the keys
|
||||
* 'delta', 'title', 'subject' (same as title) and 'content'.
|
||||
*
|
||||
* title AND subject need to be present to avoid that block module overrides
|
||||
* title.
|
||||
*/
|
||||
abstract public function render();
|
||||
}
|
56
sites/all/modules/boxes/plugins/boxes_simple.inc
Normal file
56
sites/all/modules/boxes/plugins/boxes_simple.inc
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Simple custom text box.
|
||||
*/
|
||||
class boxes_simple extends boxes_box {
|
||||
/**
|
||||
* Implementation of boxes_box::options_defaults().
|
||||
*/
|
||||
public function options_defaults() {
|
||||
return array(
|
||||
'body' => array(
|
||||
'value' => '',
|
||||
'format' => filter_default_format(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of boxes_box::options_form().
|
||||
*/
|
||||
public function options_form(&$form_state) {
|
||||
$format = filter_format_load($this->options['body']['format']);
|
||||
|
||||
if (filter_access($format)) {
|
||||
$form = array();
|
||||
$form['body'] = array(
|
||||
'#type' => 'text_format',
|
||||
'#base_type' => 'textarea',
|
||||
'#title' => t('Box body'),
|
||||
'#default_value' => $this->options['body']['value'],
|
||||
'#rows' => 6,
|
||||
'#format' => $this->options['body']['format'] ? $this->options['body']['format'] : NULL,
|
||||
'#description' => t('The content of the block as shown to the user.'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of boxes_box::render().
|
||||
*/
|
||||
public function render() {
|
||||
$content = '';
|
||||
if (!empty($this->options['body']['value']) && isset($this->options['body']['format'])) {
|
||||
$content = check_markup($this->options['body']['value'], $this->options['body']['format'], $langcode = '' /* TODO Set this variable. */, FALSE);
|
||||
}
|
||||
$title = isset($this->title) ? $this->title : NULL;
|
||||
return array(
|
||||
'delta' => $this->delta, // Crucial.
|
||||
'title' => $title,
|
||||
'subject' => check_plain($title),
|
||||
'content' => $content,
|
||||
);
|
||||
}
|
||||
}
|
45
sites/all/modules/boxes/plugins/spaces_controller_boxes.inc
Normal file
45
sites/all/modules/boxes/plugins/spaces_controller_boxes.inc
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Spaces controller for boxes module.
|
||||
*/
|
||||
class spaces_controller_boxes extends spaces_controller {
|
||||
|
||||
// Override of load_original_values
|
||||
protected function load_original_values($id = NULL) {
|
||||
if (empty($this->loaded_all['original'])) {
|
||||
// TODO can we always rely on having export.inc loaded?
|
||||
if (!isset($id)) {
|
||||
$boxes = array();
|
||||
foreach (ctools_export_load_object('box') as $box) {
|
||||
$boxes[$box->delta] = $box;
|
||||
}
|
||||
$this->values['original'] = $boxes;
|
||||
$this->loaded_all['original'] = TRUE;
|
||||
}
|
||||
else if (!isset($this->loaded['original'][$id])) {
|
||||
if ($box = array_pop(ctools_export_load_object('box', 'names', array($id)))) {
|
||||
$this->values['original'][$id] = $box;
|
||||
$this->loaded['original'][$id] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of the set() method.
|
||||
*
|
||||
* Remove flags used by to detect state and transflorm to stdClass so that the
|
||||
* box configuration can be loaded regardless of whether the plugin is
|
||||
* available.
|
||||
*/
|
||||
function set($id, $value) {
|
||||
unset($value->new);
|
||||
unset($value->export_type);
|
||||
$box = new stdClass();
|
||||
foreach ($value as $k => $v) {
|
||||
$box->$k = $v;
|
||||
}
|
||||
parent::set($id, $box);
|
||||
}
|
||||
}
|
BIN
sites/all/modules/boxes/swirly.gif
Normal file
BIN
sites/all/modules/boxes/swirly.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
165
sites/all/modules/boxes/tests/boxes.test
Normal file
165
sites/all/modules/boxes/tests/boxes.test
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
class BoxesTestCase extends DrupalWebTestCase {
|
||||
protected $profile = 'testing';
|
||||
|
||||
/**
|
||||
* Implementation of getInfo().
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => t('Boxes functionality'),
|
||||
'description' => t('Add and delete custom boxes.'),
|
||||
'group' => t('Boxes'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp(array('comment', 'ctools', 'block', 'boxes'));
|
||||
|
||||
// Create and login user
|
||||
$admin_user = $this->drupalCreateUser(array('administer blocks', 'administer boxes'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creating and deleting a box.
|
||||
*/
|
||||
function testBoxes() {
|
||||
|
||||
// Add a new box by filling out the input form on the admin/build/block/add page.
|
||||
$box = array();
|
||||
$box['description'] = $this->randomName(8);
|
||||
$box['title'] = $this->randomName(8);
|
||||
$box['body[value]'] = $this->randomName(32);
|
||||
$box['delta'] = strtolower($this->randomName(16));
|
||||
$this->drupalPost('admin/structure/block/box-add/simple', $box, t('Save'));
|
||||
|
||||
// Confirm that the box has been created, and then query the created bid.
|
||||
$this->assertText(
|
||||
t('@description has been created.', array('@description' => $box['description'])),
|
||||
t('Box successfully created.'));
|
||||
$delta = db_query("select delta from {box} where delta = :delta", array('delta' => $box['delta']))->fetchField();
|
||||
$this->assertNotNull($delta, t('box found in database'));
|
||||
|
||||
// Delete the created box & verify that it's been deleted and no longer appearing on the page.
|
||||
$this->drupalPost('admin/structure/block/manage/boxes/' . $delta . '/delete/', array(), t('Delete'));
|
||||
// TODO check confirmation message ...of course we'd need to show one first.
|
||||
$delta = db_query("select delta from {box} where delta = :delta", array('delta' => $box['delta']))->fetchField();
|
||||
$this->assertFalse($delta, t('box not found in database'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class BoxesAjaxTestCase extends DrupalWebTestCase {
|
||||
/**
|
||||
* Parse JSON that was generated by drupal_to_js
|
||||
*
|
||||
* Because of peculiarities of drupal_to_js we need to prepare our json
|
||||
* for parsing.
|
||||
*/
|
||||
function parseJSON() {
|
||||
// Step one; undo the "HTML escaping" that drupal does.
|
||||
$json = str_replace(array('\x3c', '\x3e', '\x26'), array("<", ">", "&"), $this->content);
|
||||
// Step two; handle our escaped single quotes with extreme care,
|
||||
$json = str_replace(array("\'"), array("\x27"), $json);
|
||||
// Step three; parse!
|
||||
$json = json_decode($json);
|
||||
|
||||
// JSON_ERROR_NONE == 0 in PHP 5.3
|
||||
$error = function_exists('json_last_error')
|
||||
? json_last_error()
|
||||
: $json == NULL? 1 : 0;
|
||||
|
||||
if ($error === 0) {
|
||||
$this->pass("Parsed JSON response");
|
||||
}
|
||||
else {
|
||||
$this->fail("Failed to parse JSON response");
|
||||
}
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a block via the context ajax callback and set the payload as the
|
||||
* content for simpletest.
|
||||
*/
|
||||
function ajaxLoadBoxesBlock($delta, $path = 'node') {
|
||||
$this->drupalGet($path, array('query' => array('boxes_delta' => $delta)));
|
||||
$response = $this->parseJSON();
|
||||
$block = NULL;
|
||||
foreach ($response as $command) {
|
||||
if (($command->command == 'insert') && ($command->method == 'replaceWith')) {
|
||||
$block = $command->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($block) {
|
||||
$this->pass("Loaded block");
|
||||
|
||||
// Replace contents of the reponse with the decoded JSON
|
||||
$this->content = $block;
|
||||
}
|
||||
else {
|
||||
$this->fail('Failed to load block');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BoxesBasicAjaxTestCase extends BoxesAjaxTestCase {
|
||||
/**
|
||||
* Implementation of getInfo().
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => t('Boxes Ajax functionality'),
|
||||
'description' => t('Add a custom boxes with AJAX.'),
|
||||
'group' => t('Boxes'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp('ctools', 'context', 'boxes');
|
||||
|
||||
// Create and login user
|
||||
$admin_user = $this->drupalCreateUser(array('administer blocks', 'administer boxes'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creating and deleting a box.
|
||||
*/
|
||||
function testAjaxBoxes() {
|
||||
$this->ajaxLoadBoxesBlock('boxes_add__simple');
|
||||
$this->assertText(t('Add custom box'), 'Found box add form');
|
||||
|
||||
$edit = array(
|
||||
'description' => $this->randomName(),
|
||||
'title' => $this->randomName(),
|
||||
'body[value]' => $this->randomName(32),
|
||||
);
|
||||
$this->drupalPost(NULL, $edit, t('Save'), array('query' => array('boxes_delta' => 'boxes_add__simple')));
|
||||
$response = $this->parseJSON();
|
||||
$delta = NULL;
|
||||
foreach ($response as $command) {
|
||||
if ($command->command == 'getBlock') {
|
||||
$delta = $command->delta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$delta) {
|
||||
$this->fail('AJAX block submission failed');
|
||||
}
|
||||
|
||||
$this->ajaxLoadBoxesBlock($delta);
|
||||
$this->assertText($edit['title'], 'Found box');
|
||||
}
|
||||
}
|
||||
|
118
sites/all/modules/boxes/tests/boxes_spaces.test
Normal file
118
sites/all/modules/boxes/tests/boxes_spaces.test
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
class BoxesSpacesTestCase extends BoxesAjaxTestCase {
|
||||
/**
|
||||
* Implementation of getInfo().
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => t('Boxes Spaces functionality'),
|
||||
'description' => t('Add custom boxes in Spaces.'),
|
||||
'group' => t('Boxes'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp('ctools', 'boxes', 'features', 'purl', 'spaces', 'spaces_ui', 'spaces_user', 'taxonomy', 'spaces_taxonomy');
|
||||
|
||||
// Create and login user
|
||||
$admin_user = $this->drupalCreateUser(array(
|
||||
'administer blocks',
|
||||
'administer boxes',
|
||||
'administer spaces',
|
||||
'administer site configuration',
|
||||
'administer taxonomy',
|
||||
));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
function runTest($path) {
|
||||
$this->ajaxLoadBoxesBlock('boxes_add__simple', $path);
|
||||
$this->assertResponse('200', 'Response code 200');
|
||||
$this->assertText(t('Add custom box'), 'Found box add form');
|
||||
|
||||
$edit = array(
|
||||
'description' => $this->randomName(),
|
||||
'title' => $this->randomName(),
|
||||
'body' => $this->randomName(32),
|
||||
);
|
||||
$this->drupalPost(NULL, $edit, t('Save'));
|
||||
$response = $this->parseJSON();
|
||||
$delta = null;
|
||||
foreach ($response as $command) {
|
||||
if ($command->command == 'getBlock') {
|
||||
$delta = $command->delta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$delta) {
|
||||
$this->fail('AJAX block submission failed');
|
||||
}
|
||||
|
||||
$this->ajaxLoadBoxesBlock($delta, $path);
|
||||
$this->assertResponse('200', 'Response code 200');
|
||||
$this->assertText($edit['title'], 'Found box');
|
||||
|
||||
$this->ajaxLoadBoxesBlock($delta, 'node');
|
||||
$this->assertNoText($edit['title'], "Block not available outside spaces.");
|
||||
return $delta;
|
||||
}
|
||||
|
||||
function testUserSpace() {
|
||||
$delta = $this->runTest('user/3');
|
||||
|
||||
// Before this final check we make sure that user/%uid/features/override
|
||||
// path is actually available. Some of our caches are over exuberant.
|
||||
$this->drupalPost('admin/config/development/performance', array(), t('Clear cached data'));
|
||||
|
||||
$this->drupalGet('user/3/features/overrides');
|
||||
$this->assertResponse('200', 'Response code 200');
|
||||
$this->assertText($delta, 'Found overridden box: ' . $delta);
|
||||
}
|
||||
|
||||
function testTermSpace() {
|
||||
// Setup; set the purl type to path.
|
||||
$edit = array('purl_types[path]' => 'path');
|
||||
$this->drupalPost('admin/config/purl/types', $edit, t('Save configuration'));
|
||||
|
||||
// Setup; enable path prefixing for taxonomy spaces.
|
||||
$edit = array('purl_method_spaces_taxonomy' => 'path');
|
||||
$this->drupalPost('admin/config/purl', $edit, t('Save configuration'));
|
||||
|
||||
// Setup; create a vocabulary.
|
||||
$edit = array(
|
||||
'name' => $this->randomName(),
|
||||
'module' => strtolower($this->randomName()),
|
||||
);
|
||||
$this->drupalPost('admin/structure/taxonomy/add/vocabulary', $edit, t('Save'));
|
||||
|
||||
// Setup; Enable this vocab for spaces_taxonomy.
|
||||
$edit = array('spaces_taxonomy_vid' => '1');
|
||||
$this->drupalPost('admin/structure/spaces/taxonomy', $edit, t('Save configuration'));
|
||||
|
||||
// Setup; Create our term space.
|
||||
$edit = array(
|
||||
'name' => $this->randomName(),
|
||||
'purl[value]' => strtolower($this->randomName()),
|
||||
);
|
||||
$this->drupalPost('admin/structure/taxonomy/1/add/term', $edit, t('Save'));
|
||||
|
||||
// Testing!
|
||||
$prefix = $edit['purl[value]'];
|
||||
$this->drupalGet($prefix . '/node');
|
||||
$this->assertResponse('200', 'Response code 200');
|
||||
|
||||
$delta = $this->runTest($prefix . '/node');
|
||||
|
||||
// Before this final check we make sure that user/%uid/features/override
|
||||
// path is actually available. Some of our caches are over exuberant.
|
||||
$this->drupalPost('admin/config/development/performance', array(), t('Clear cached data'));
|
||||
|
||||
$this->drupalGet('taxonomy/term/1/features/overrides');
|
||||
$this->assertResponse('200', 'Response code 200');
|
||||
$this->assertText($delta, 'Found overridden box: ' . $delta);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user