first import

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-08 11:40:19 +02:00
commit 1bc61b12ad
8435 changed files with 1582817 additions and 0 deletions

View 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.

View File

@@ -0,0 +1,167 @@
Features Override (Drupal 7-2.x)
--------------------------------
This module add a new Features exportable called "Feature Overrides" that
are used to export overridden changes to other Features. It requires at
least the 7.x-1.0-rc1 release of Features.
To use, install this module and enable it. When you create a new feature from
the Structure/Features page, two new exportables called "Feature Overrides"
will be displayed in the drop-down list. The first one allows you to override
all of the changes of a specific component. The second "Individual Advanced"
allows you to select exactly which line-by-line changes are exported.
Select the Overrode exportable and then select which components you wish to
export overrides for. Only components that are currently overridden will be
shown as checkboxes.
Maintainers
-----------
- mpotter (Mike Potter)
Basic Usage
-----------
1) Create normal features and enable them.
2) Make changes to the site using the normal Drupal UI.
3) Go to the admin/structure/features page and you should see some of your
Features marked as "Overridden"
4) Click the "Create Feature" tab.
5) Enter a name for your Override feature.
6) Click the "Edit components" drop-down and select "Feature Overrides".
A list of overridden components will be shown. For example, if you changed a
field in a content type, that field name will be shown in the list of
overrides. If you changed something in a view, that view name will be in the
list. Check the boxes next to the overrides you wish to save.
7) Click the "Download Feature" button at the bottom of the screen. This will
create your Override Feature module code and save it to a local file. Upload
that file to your server and place it into your normal sites/all/modules
directory.
8) Go to the Modules page and Enable your new override module.
9) Clear the Drupal cache.
10) Now when you visit the admin/structure/features you should see your new
override feature and the original features should no longer be marked as
"Overridden".
Merging new changes into an existing Override
---------------------------------------------
Once you have created an Override feature, it's easy to add additional changes
to it:
1) Make changes to the site via the Drupal UI
2) Visit admin/structure/features and you should see both the original code
feature marked as "Overridden" as well as the Override feature marked as
"Overridden"
3) Click the Recreate link for the Override feature.
4) Select any new overrides from the Component dropdown list as needed.
Download your new feature.
You can accomplish this same task using Drush:
drush features-update override-feature
5) Now visit the Features admin page and nothing should be marked as Overridden
again.
NOTE: You want to update/recreate the Override feature and NOT the original
feature. If you recreate the original feature, then ALL of the overrides (the
existing ones in the Override module and the new changes) will be written to
the original feature. Probably not what you wanted (see next section)
Rebuilding the Original Feature without the Overrides
-----------------------------------------------------
Sometimes you want to make a change and have that change saved with the
original feature and not with the Override. Here are the steps to accomplish
this:
1) Make the changes you need to the site via the Drupal UI
2) Visit admin/structure/features and you should see both the original code
feature marked as "Overridden" as well as the Override feature marked as
"Overridden"
3) Click the "Create Feature" tab to create a new feature
4) Create a new Override feature by entering a name and description, then
select the overrides you want to save from the Feature Override section of the
Components drop-down menu
5) Click Download Feature and install this new module on your site. Let's
call it "New Changes". So now we have the "Original Feature", the first
"Override Feature", and the new "New Changes" feature. All three should
display in the Features Admin page in their Default state.
6) From the Features Admin page, uncheck the "New Changes" feature you created
in step 5, then click Save. This will undo the recent changes.
7) From the Features Admin page, uncheck the box next to the "Override Feature"
that you originally created (NOT the New one you made in step 5) and click
Save. This will undo the changes made by the first Override module.
8) If the original feature shows as "Overridden" or "Needs Review", click on
it and click the Revert button to ensure it is in it's original state.
9) From the Features Admin page, check the box next to the "New Changes"
feature you created in step 5 to enable is and click Save. Now the database
reflects the original feature plus the new changes.
10) Click the Recreate link for the original Feature. Click the Download link
and install the updated feature. Or use the drush command:
"drush features-update original-feature". This will export the original
feature code along with the New Changes code.
11) You no longer need the New Changes feature. You can disable it and remove
it from your site if you wish. If you don't remove it completely, at least
ensure that it is disabled in the Feature Admin page.
12) Finally, check the box next to the Override feature to re-enable that
feature. Now you have the original code plus the New changes stored in the
original feature, but you still have the additional Overrides in the seperate
Override module.
Once you understand the above steps you will also realize that there are other
ways to accomplish this same task. For example, you could have disabled the
Override module first, then made your changes and just recreated the original
feature directly. However, the above procedure is the most complete and
reflects the real-life situation where the changes have already been made to
the site and you need to somehow capture those changes back into the original
feature.
Adding or Removing specific Override lines
------------------------------------------
An Override feature is simply a list of code changes that need to be made to
the current configuration. Only code *differences* are stored in the Override
feature.
To view these specific line-by-line code differences, click the Default link
next to your Override module from the Features admin page, then click the
Review Overrides tab. This will show the Overrides currently exported as
individual lines (along with the normal "diff" listing below).
To change which specific lines are exported, click the Recreate tab, then
open the Components dropdown. Select the "Features Overrides Individual"
(advanced) tab. Then click the "Refine" link next to the component you want
to adjust. Each specific override line will be shown as a checkbox. Simply
check or uncheck the lines desired. Then click the Download button to create
a new version of your Override feature.
In the main Features Admin page there is also a new Review Overrides tab.
This will show a list of any new overrides no matter which module that relate
to. This is a very useful debugging tool for determining where changes have
been made to your site. The Overrides tab will tell you the exact Component
being overridden. The normal "Review Overrides" tab in Features only shows the
raw code "diffs" and sometimes cannot show the full context of the change. The
new Review Overrides tab can show you exactly what the change is and where it
is made (which View changed, which field changed, etc).

View File

@@ -0,0 +1,122 @@
<?php
/**
* @file
* Page callbacks features overrides admin pages.
*/
/**
* Renders the differences for a component and element
*/
function features_override_render_differences($component = '', $element = '', $module = '') {
module_load_include('inc', 'features_override', 'features_override.export');
module_load_include('inc', 'features', 'features.export');
drupal_add_css(drupal_get_path('module', 'features_override') . '/features_override.css');
if (empty($module)) {
$differences = features_override_get_overrides($component, $element, TRUE, !empty($component));
}
else {
// only grab the differences for the specific module we are interested in
$differences = array();
foreach ($module->info['features'] as $comp_name => $comp) {
if ($difference = array_filter(features_override_module_component_overrides($module->name, $comp_name, FALSE, TRUE))) {
$differences[$comp_name] = isset($differences[$comp_name]) ? array_merge($difference, $differences[$comp_name]) : $difference;
}
}
}
if (!$differences || !count(array_filter($differences))) {
return t('No overrides were found.');
}
if (!empty($element)) {
$differences = array($element => $differences);
}
if (!empty($component)) {
$differences = array($component => $differences);
}
$rows = array();
foreach ($differences as $component_name => $item) {
$code_change = array();
$code_add = array();
$code_delete = array();
foreach ($item as $element_name => $difference) {
$key = (isset($_GET['key'])) ? $_GET['key'] : '';
if (!empty($key)) {
if (!empty($difference['additions'][$key])) {
return '<pre>' . check_plain(implode("\n",
features_override_features_export_render_addition($difference['additions'][$key], $element_name, $component_name))) .
'</pre>';
}
elseif (!empty($difference['deletions'][$key])) {
return '<pre>' . check_plain(implode("\n",
features_override_features_export_render_deletion($difference['deletions'][$key], $element_name, $component_name))) .
'</pre>';
}
else {
return t('Unable to find referenced information.');
}
}
else {
if (!empty($difference['additions'])) {
foreach ($difference['additions'] as $alter) {
if (is_scalar($alter['value'])) {
$code_change[] = array('<pre>' . check_plain(implode("\n", features_override_features_export_render_addition($alter, $element_name, $component_name))). '</pre>');
}
else {
$code_add[] = array('<pre>' . check_plain(implode("\n", features_override_features_export_render_addition($alter, $element_name, $component_name, FALSE))). '</pre>');
}
}
}
if (!empty($difference['deletions'])) {
foreach ($difference['deletions'] as $alter) {
$code_delete[] = array('<pre>' . check_plain(implode("\n", features_override_features_export_render_deletion($alter, $element_name, $component_name))). '</pre>');
}
}
}
}
if (count($code_add) || count($code_delete) || count($code_change)) {
$rows[] = array(array('data' => $component_name, 'header' => TRUE));
}
if (count($code_change)) {
$rows[] = array('CHANGES');
$rows = array_merge($rows, $code_change);
}
if (count($code_add)) {
$rows[] = array('ADDITIONS');
$rows = array_merge($rows, $code_add);
}
if (count($code_delete)) {
$rows[] = array('DELETIONS');
$rows = array_merge($rows, $code_delete);
}
}
return theme('table', array('rows' => $rows, 'attributes' => array('class' => 'features_override_table')));
}
/**
* Page callback to display the differences between what's in code and
* what is in the db.
*
* @param $feature
* A loaded feature object to display differences for.
* @param $component
* Optional: specific component to display differences for. If excluded, all components are used.
*
* @return Themed display of what is different.
*/
function features_override_feature_diff($feature, $component = NULL) {
if (module_exists('diff')) {
module_load_include('inc', 'features', 'features.admin');
$output = features_feature_diff($feature, $component);
$output['diff'] = array(
'#prefix' => '<h2>',
'#markup' => 'Code diff',
'#suffix' => '</h2>',
'#weight' => -98,
);
}
$output['overrides'] = array(
'#markup' => features_override_render_differences('', '', $feature),
'#weight' => -99,
);
return $output;
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Autogenerated hook that duplicates what alters are being exported via
* features overrides.
*
* This hook should only ever be auto-exported.
*/
function hook_features_override_default() {
return array();
}
/**
* Allows modules to clean up the default and normal components.
*
* For whatever reason, extra information or inconstancies may be introduced
* into the normal (current) or default (defined) components. This hook allows
* modules to hook in and clean up whatever they need to.
*
* @param $default
* The object or array as defined in a default hook, unaltered.
* @param $normal
* The current object, either the current default + alters or database
* overrides.
* @param $context
* an array containing module and component information.
*/
function hook_features_override_component_overrides_alter(&$default, &$normal, $context) {
if ($context['component'] == 'views_view') {
unset($normal->api_version);
}
}
/**
* Component hook. The hook should be implemented using the name ot the
* component, not the module, eg. [component]_features_export() rather than
* [module]_features_export().
*
* Renders an addition to a feature.
*
* @return string
* A rendered string.
* @see features_override_export_render_addition();
*/
function hook_features_override_export_render_addition() {
}
/**
* Component hook. The hook should be implemented using the name ot the
* component, not the module, eg. [component]_features_export() rather than
* [module]_features_export().
*
* Renders a deletion to a feature.
*
* @return string
* A rendered string.
* @see features_override_export_render_deletion();
*/
function hook_features_override_export_render_deletion() {
}

View File

@@ -0,0 +1,45 @@
div.form-item.form-type-checkbox {
padding: 0;
}
table.features_override_table td {
padding: 4px 10px;
}
table.features_override_table td pre {
margin: 0 0;
line-height: 150%;
}
#edit-sources-features-overrides {
overflow-y: visible;
height: auto;
margin-bottom: 8px;
}
#edit-sources-features-overrides h4 {
background: #E1E2DC;
border: 1px solid #BEBFB9;
margin: 6px 0;
padding: 4px 5px;
font-weight: normal;
}
a.features_override_button {
color: #333;
background: #EEE;
padding: 0px 5px;
margin-right: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
float: right;
}
#edit-sources-features-overrides h4 a {
color: #333;
background: #CCC;
margin-right: 0;
}
a.features_override_button:hover {
background: #DEF;
}
#edit-sources-features-overrides h4 a.features_override_button:hover {
background: #DEF;
}
#edit-sources-features-overrides div.form-type-checkbox {
clear: right;
}

View File

@@ -0,0 +1,571 @@
<?php
/**
* @file
* Helper function to export features overrides.
*/
/**
* Parses the identifier into indivudal parts.
*
* As the keys may have a period in them, cannot use explode or similair ways.
*
* @param $identifier
* A string in the form <comonent>.<element>.<keys> or <component>.<element>.
* @return
* An array of component, element, and keys string
* @see features_override_make_key()
*/
function features_override_parse_identifier($identifier) {
$first_period = strpos($identifier, '.');
$component = substr($identifier, 0, $first_period);
if ($second_period = strpos($identifier, '.', $first_period + 1)) {
$element = substr($identifier, $first_period + 1, $second_period - $first_period - 1);
$keys = substr($identifier, $second_period + 1);
}
else {
$element = substr($identifier, $first_period + 1);
$keys = FALSE;
}
return array($component, $element, $keys);
}
/**
* Makes a distinct string key from an array of keys.
*
* @param $keys
* An array of keys.
* @return
* A string representation of the keys.
*/
function features_override_make_key($keys) {
if (is_array($keys)) {
$return_keys = array();
foreach ($keys as $key) {
$return_keys[] = $key['key'];
}
return implode('|', $return_keys);
}
else {
return $keys;
}
}
/**
* Returns an array of keys to be ignored for various exportables
* @param $component
* The component to retrieve ignore_keys from.
*/
function features_get_ignore_keys($component) {
static $cache;
if (!isset($cache[$component])) {
$cache[$component] = module_invoke_all('features_override_ignore', $component);
}
return $cache[$component];
}
/**
* Calculautes what overrides exist for by component/element.
*
* @param $component_key
* A component key that's defined via hook_features_api.
* @param $element_key
* A key identifieing an element that's been overriden.
* @param $reset
* Reset the internal cache of overrides gathered.
* @param $all
* If TRUE, return all overrides, otherwise only overrides not yet in an override feature
* */
function features_override_get_overrides($component_key = FALSE, $element_key = FALSE, $reset = FALSE, $all = TRUE) {
static $cache;
if (!isset($cache) || $reset) {
$cache = array();
module_load_include('inc', 'features', 'features.export');
features_include();
foreach (features_get_components() as $component => $info) {
if (empty($info['default_hook']) || $component == 'features_override_items' || $component == 'features_overrides' || !features_get_default_alter_hook($component) | !features_hook($component, 'features_export_render')) {
continue;
}
features_include_defaults($component);
foreach (module_implements($info['default_hook']) as $module) {
if ($differences = array_filter(features_override_module_component_overrides($module, $component, $reset, $all))) {
$cache[$component] = isset($cache[$component]) ? array_merge($differences, $cache[$component]) : $differences;
}
}
$cache[$component] = isset($cache[$component]) ? array_filter($cache[$component]) : array();
}
}
if ($component_key && $element_key) {
return !empty($cache[$component_key][$element_key]) ? $cache[$component_key][$element_key] : array();
}
elseif ($component_key) {
return !empty($cache[$component_key]) ? $cache[$component_key] : array();
}
return $cache;
}
/**
* Get overrides for specific module/component.
*
* @param $module
* An enabled module to find overrides for it's components.
* @param $component
* A type of component to find overrides for.
* @param $reset
* Reset the internal cache of overrides gathered.
* @param $all
* If TRUE, return all overrides, otherwise only overrides not yet in an override feature
* @return
* An array of overrides found.
*/
function features_override_module_component_overrides($module, $component, $reset = FALSE, $all = TRUE) {
static $cache = array();
if (isset($cache[$module][$component]) && !$reset) {
return $cache[$module][$component];
}
module_load_include('inc', 'features_override', 'features_override.hooks');
features_include();
features_include_defaults($component);
// Allows overriding non-feature controlled code.
$default_hook = features_get_default_hooks($component);
if ($all) {
// call hooks directly
// could also do
// $default = features_get_default($component, $module, FALSE, $reset);
// but this is more efficient
$default = module_invoke($module, $default_hook);
}
else {
$default = features_get_default($component, $module, TRUE, $reset);
}
$normal = features_get_normal($component, $module, $reset);
// This indicates it is likely not controlled by features, so fetch manually.
if (!$normal && is_array($default)) {
$code = array_pop(features_invoke($component, 'features_export_render', $module, array_keys($default), NULL));
if (!$code) {
return FALSE;
}
else {
$normal = eval($code);
}
}
$context = array(
'component' => $component,
'module' => $module,
);
// Can't use _features_sanitize as that resets some keys.
_features_override_sanitize($normal);
_features_override_sanitize($default);
// make a deep copy of data to prevent problems when removing recursion later
$default_copy = unserialize(serialize($default));
$normal_copy = unserialize(serialize($normal));
$ignore_keys = features_get_ignore_keys($component);
// remove keys to be ignored
// doing this now allows us to better control which recursive parts are removed
if (count($ignore_keys)) {
_features_override_remove_ignores($default_copy, $ignore_keys);
_features_override_remove_ignores($normal_copy, $ignore_keys);
}
// now remove any remaining recursion
features_override_remove_recursion($default_copy);
features_override_remove_recursion($normal_copy);
$component_overrides = array();
if ($normal && is_array($normal) || is_object($normal)) {
foreach ($normal as $name => $properties) {
$component_overrides[$name] = array(
'additions' => array(),
'deletions' => array(),
);
if (isset($default_copy[$name])) {
drupal_alter('features_override_component_overrides', $default_copy[$name], $normal_copy[$name], $context);
_features_override_set_additions($default_copy[$name], $normal_copy[$name], $component_overrides[$name]['additions'], $ignore_keys);
_features_override_set_deletions($default_copy[$name], $normal_copy[$name], $component_overrides[$name]['deletions'], $ignore_keys);
}
if (!array_filter($component_overrides[$name])) {
$component_overrides[$name] = FALSE;
}
}
// now check for any elements that are in $default but not in $normal that we didn't process yet
foreach ($default as $name => $properties) {
if (!isset($normal_copy[$name])) {
$_keys = array(array('type' => 'array', 'key' => $name));
$component_overrides[$name]['deletions'][features_override_make_key($name)] = array(
'keys' => $name,
);
}
}
}
$cache[$module][$component] = $component_overrides;
return $component_overrides;
}
/**
* Sorts an array by its keys (assoc) or values (non-assoc).
*
* @param $array
* An array that needs to be sorted.
*/
function _features_override_sanitize(&$array) {
if (is_array($array)) {
$is_assoc = (array_keys($array) !== range(0, count($array) - 1));
if ($is_assoc) {
ksort($array);
}
else {
sort($array);
}
foreach ($array as $k => $v) {
if (is_array($v)) {
_features_override_sanitize($array[$k]);
}
}
}
}
/**
* Helper function to set the additions between default and normal features.
*
* @param $default
* The default defination of a component.
* @param $normal
* The current defination of a component.
* @param $additions
* An array of currently gathered additions.
* @param $ignore_keys
* Keys to ignore while processing element.
* @param $level
* How many levels deep into object.
* @param $keys
* The keys for this level.
*/
function _features_override_set_additions(&$default, &$normal, &$additions, $ignore_keys = array(), $level = 0, $keys = array()) {
$object = is_object($normal);
foreach ($normal as $key => $value) {
if (isset($ignore_keys[$key]) && ($level == $ignore_keys[$key])) {
continue;
}
if ($object) {
if (!is_object($default) || !property_exists($default, $key) || (is_scalar($value) && ($default->$key !== $value))) {
$_keys = array_merge($keys, array(array('type' => 'object', 'key' => $key)));
$additions[features_override_make_key($_keys)] = array(
'keys' => $_keys,
'value' => $value,
'original' => (is_scalar($value) && isset($default->$key)) ? $default->$key : '',
);
}
elseif (property_exists($default, $key) && ($default->$key !== $value)) {
_features_override_set_additions($default->$key, $value, $additions, $ignore_keys, $level+1, array_merge($keys, array(array('type' => 'object', 'key' => $key))));
}
}
elseif (is_array($normal)) {
if (!is_array($default) || !array_key_exists($key, $default) || (is_scalar($value) && ($default[$key] !== $value))) {
$_keys = array_merge($keys, array(array('type' => 'array', 'key' => $key)));
$additions[features_override_make_key($_keys)] = array(
'keys' => $_keys,
'value' => $value,
'original' => (is_scalar($value) && isset($default[$key])) ? $default[$key] : '',
);
}
elseif (array_key_exists($key, $default) && (!is_null($value) && ($default[$key] !== $value))) {
_features_override_set_additions($default[$key], $value, $additions, $ignore_keys, $level+1, array_merge($keys, array(array('type' => 'array', 'key' => $key))));
}
}
}
}
/**
* Helper function to set the deletions between default and normal features.
*
* @param $default
* The default defination of a component.
* @param $normal
* The current defination of a component.
* @param $deletions
* An array of currently gathered deletions.
* @param $ignore_keys
* Keys to ignore while processing element.
* @param $level
* How many levels deep into object.
* @param $keys
* The keys for this level.
*/
function _features_override_set_deletions(&$default, &$normal, &$deletions, $ignore_keys = array(), $level = 0, $keys = array()) {
$object = is_object($default);
foreach ($default as $key => $value) {
if (isset($ignore_keys[$key]) && ($level == $ignore_keys[$key])) {
continue;
}
if ($object) {
if (!property_exists($normal, $key)) {
$_keys = array_merge($keys, array(array('type' => 'object', 'key' => $key)));
$deletions[features_override_make_key($_keys)] = array(
'keys' => $_keys,
);
}
elseif (property_exists($normal, $key) && (is_array($value) || is_object($value))) {
_features_override_set_deletions($value, $normal->$key, $deletions, $ignore_keys, $level+1, array_merge($keys, array(array('type' => 'object', 'key' => $key))));
}
}
else {
if (!array_key_exists($key, $normal)) {
$_keys = array_merge($keys, array(array('type' => 'array', 'key' => $key)));
$deletions[features_override_make_key($_keys)] = array(
'keys' => $_keys,
);
}
elseif (array_key_exists($key, $normal) && (is_array($value) || is_object($value))) {
_features_override_set_deletions($value, $normal[$key], $deletions, $ignore_keys, $level+1, array_merge($keys, array(array('type' => 'array', 'key' => $key))));
}
}
}
}
/**
* Creates a string representation of an array of keys.
*
* @param $keys
* An array of keys with their associate types.
*
* @return
* A string representation of the keys.
*/
function features_override_export_keys($keys) {
$line = '';
if (is_array($keys)) {
foreach ($keys as $key) {
if ($key['type'] == 'object') {
$line .= "->{$key['key']}";
}
else {
$line .= "['{$key['key']}']";
}
}
}
return $line;
}
/**
* Removes recursion from an object or array.
*
* @param $item
* An object or array passed by reference.
*/
function features_override_remove_recursion(&$item) {
_features_override_remove_recursion($item);
_features_override_remove_recursion_markers($item);
}
/**
* Helper to removes recursion from an object/array.
*
* @param $item
* An object or array passed by reference.
*/
function _features_override_remove_recursion(&$item) {
$is_object = is_object($item);
if ($is_object) {
$item->{FEATURES_OVERRIDE_RECURSION_MARKER} = 1;
}
else {
$item[FEATURES_OVERRIDE_RECURSION_MARKER] = 1;
}
foreach ($item as $key => $value) {
if (is_array($value) || is_object($value)) {
$remove = is_array($value) ? !empty($value[FEATURES_OVERRIDE_RECURSION_MARKER]) : !empty($value->{FEATURES_OVERRIDE_RECURSION_MARKER});
if ($remove) {
if ($is_object) {
unset($item->$key);
}
else {
unset($item[$key]);
}
}
else {
features_override_remove_recursion($value);
}
}
}
}
/**
* Helper to removes recursion from an object/array.
*
* @param $item
* An object or array passed by reference.
*/
function _features_override_remove_recursion_markers(&$item) {
$is_object = is_object($item);
foreach ($item as $key => $value) {
if ($key === FEATURES_OVERRIDE_RECURSION_MARKER) {
if ($is_object) {
unset($item->$key);
}
else {
unset($item[$key]);
}
}
elseif (is_array($value) || is_object($value)) {
_features_override_remove_recursion_markers($value);
}
}
}
/**
* Helper to removes a set of keys an object/array.
*
* @param $item
* An object or array passed by reference.
* @param $ignore_keys
* Array of keys to be ignored. Values are the level of the key.
* @param $level
* Level of key to remove. Up to 2 levels deep because $item can still be
* recursive
*/
function _features_override_remove_ignores(&$item, $ignore_keys, $level = -1) {
$is_object = is_object($item);
foreach ($item as $key => $value) {
if (isset($ignore_keys[$key]) && ($ignore_keys[$key] == $level)) {
if ($is_object) {
unset($item->$key);
}
else {
unset($item[$key]);
}
}
elseif (($level < 2) && (is_array($value) || is_object($value))) {
_features_override_remove_ignores($value, $ignore_keys, $level+1);
}
}
}
/**
* Drupal-friendly var_export().
*
* @param $var
* The variable to export.
* @param $prefix
* A prefix that will be added at the beginning of every lines of the output.
* @return
* The variable exported in a way compatible to Drupal's coding standards.
*/
function features_override_var_export($var, $prefix = '') {
if (is_array($var) || is_object($var)) {
// Special causing array so calls features_override_var_export instead of
// features_var_export.
if (is_array($var)) {
if (empty($var)) {
$output = 'array()';
}
else {
$output = "array(\n";
foreach ($var as $key => $value) {
// Using normal var_export on the key to ensure correct quoting.
$output .= " " . var_export($key, TRUE) . " => " . features_override_var_export($value, ' ', FALSE) . ",\n";
}
$output .= ')';
}
}
// Objects do not export cleanily.
else {
if (method_exists($var, 'export')) {
$output = $var->export();
}
elseif (get_class($var) === 'stdClass') {
$output = '(object) ' . features_override_var_export((array) $var, $prefix);
}
elseif (!method_exists($var, '__set_state')) {
// Ugly, but custom object with no clue how to export.without
// __set_state class and var_export produces unusable code.
$output = 'unserialize(' . var_export(serialize($var), TRUE) . ')';
}
else {
$output = var_export($var, TRUE);
}
}
}
else {
module_load_include('inc', 'features', 'features.export');
$output = features_var_export($var);
}
if ($prefix) {
$output = str_replace("\n", "\n$prefix", $output);
}
return $output;
}
/**
* Renders the addition/change to an element.
*/
function features_override_features_export_render_addition($alter, $element, $component, $is_change = TRUE) {
module_load_include('inc', 'features_override', 'features_override.hooks');
if (features_hook($component, 'features_override_export_render_addition')) {
return features_invoke($component, 'features_override_export_render_addition', $alter, $element);
}
else {
$code = array();
$component_start = "\$data['$element']";
$code_line = features_override_export_keys($alter['keys']);
$value_export = features_override_var_export($alter['value'], ' ');
if ($is_change) {
$original_export = (isset($alter['original'])) ? ' /* WAS: ' . features_override_var_export($alter['original'], ' ') . ' */' : '';
}
else {
$original_export = '';
}
$code[] = " " . $component_start . $code_line . ' = ' . $value_export . ';' . $original_export;
return $code;
}
}
/**
* Renders the deletion to an element.
*/
function features_override_features_export_render_deletion($alter, $element, $component) {
module_load_include('inc', 'features_override', 'features_override.hooks');
if (features_hook($component, 'features_override_export_render_deletion')) {
return features_invoke($component, 'features_override_export_render_deletion', $alter, $element);
}
else {
$code = array();
$component_start = "\$data['$element']";
$code_line = features_override_export_keys($alter['keys']);
$code[] = ' unset(' . $component_start . $code_line . ');';
return $code;
}
}
/**
* Encodes a string for use as option.
* @see features_dom_encode_options()
* @param $string
* A string to encode.
* @return
* An encoded string for use as option value.
*/
function features_override_encode_string($string) {
$replacements = array(
':' => '__'. ord(':') .'__',
'/' => '__'. ord('/') .'__',
',' => '__'. ord(',') .'__',
'.' => '__'. ord('.') .'__',
'<' => '__'. ord('<') .'__',
'>' => '__'. ord('>') .'__',
);
return strtr($string, $replacements);
}

View File

@@ -0,0 +1,295 @@
<?php
/**
* @file
* Page callback for features override pages.
*/
module_load_include('inc', 'features_override', 'features_override.export');
/**
* Implements hook_features_export_options().
*/
function features_override_items_features_export_options() {
$options = $links = array();
$overrides = features_override_get_overrides();
foreach ($overrides as $component => $elements) {
foreach ($elements as $key => $element) {
$options["{$component}.{$key}"] = "{$component} {$key} ";
}
}
return $options;
}
/**
* Implements hook_features_export_options().
*/
function features_overrides_features_export_options() {
$options = $sub_links = $main_links = array();
drupal_add_js(drupal_get_path('module', 'features_override') . '/features_override_form.js');
drupal_add_css(drupal_get_path('module', 'features_override') . '/features_override.css');
$overrides = features_override_get_overrides();
foreach ($overrides as $component => $elements) {
foreach ($elements as $key => $element) {
$identifier = "{$component}.{$key}";
$identifier_spaced = "{$component} {$key} ";
$main_links[features_override_encode_string($identifier)] = url('admin/structure/features/features_override/' . $component . '/' . $key);
if (!empty($element['additions'])) {
foreach ($element['additions'] as $change_key => $changes) {
$options[$identifier . '.' . $change_key] = $identifier_spaced . ' addition: of ' . features_override_export_keys($changes['keys']);
$sub_links[features_override_encode_string($identifier . '.' . $change_key)] = url('admin/structure/features/features_override/' . $component . '/' . $key, array('query' => array('key' => $change_key)));
}
}
if (!empty($element['deletions'])) {
foreach ($element['deletions'] as $change_key => $changes) {
$options[$identifier . '.' . $change_key] = $identifier_spaced . ' deletion of ' . features_override_export_keys($changes['keys']);
$sub_links[features_override_encode_string($identifier . '.' . $change_key)] = url('admin/structure/features/features_override/' . $component . '/' . $key, array('query' => array('key' => $change_key)));
}
}
}
}
drupal_add_js(array('features_override_links' => array('main' => $main_links, 'sub' => $sub_links)), 'setting');
return $options;
}
/**
* Implements hook_features_export().
*/
function features_override_items_features_export($data, &$export, $module_name = '') {
$pipe = array('features_overrides' => array());
$map = features_get_default_map('features_override_items');
$map_overrides = features_get_default_map('features_overrides');
static $options;
if (!isset($options)) {
$options = features_overrides_features_export_options();
}
foreach ($data as $identifier) {
// If this override bundle is already provided by another module, remove the field
// and add the other module as a dependency.
if (isset($map[$identifier]) && $map[$identifier] != $module_name) {
if (isset($export['features']['features_override_items'][$identifier])) {
unset($export['features']['features_override_items'][$identifier]);
}
$module = $map[$identifier];
$export['dependencies'][$module] = $module;
}
// If the field has not yet been exported, add it
else {
$export['features']['features_override_items'][$identifier] = $identifier;
list($component, $element) = features_override_parse_identifier($identifier);
// Add in all current overrides to import.
foreach ($options as $option_key => $option_name) {
list($options_component, $options_element, $options_keys) = features_override_parse_identifier($option_key);
if ($options_element == $element && empty($map_overrides[$option_key])) {
$pipe['features_overrides'][] = $option_key;
}
}
// Add in depedency to module that defines this item.
$component_map = features_get_default_map($component);
if (!empty($component_map[$element])) {
$export['dependencies'][$component_map[$element]] = $component_map[$element];
}
}
}
return $pipe;
}
/**
* Implements hook_features_export().
*/
function features_overrides_features_export($data, &$export, $module_name = '') {
$pipe = array('features_overrides' => array());
$map = features_get_default_map('features_overrides');
static $options;
foreach ($data as $identifier) {
// If this override bundle is already provided by another module, remove the field
// and add the other module as a dependency.
if (isset($map[$identifier]) && $map[$identifier] != $module_name) {
if (isset($export['features']['features_overrides'][$identifier])) {
unset($export['features']['features_overrides'][$identifier]);
}
$module = $map[$identifier];
$export['dependencies'][$module] = $module;
}
// If the field has not yet been exported, add it
else {
$export['features']['features_overrides'][$identifier] = $identifier;
}
}
return $pipe;
}
/**
* Implements hook_features_export_render().
*/
function features_override_items_features_export_render($module, $data, $export = NULL) {
// no code is needed for this exportable. Details are stored via features_overrides_features_export_render
$list = array();
/*
// Go through all data collecting the items exports to create.
$features_override_code = array(
' // This code is only used to work nicely with features UI.',
' $overrides = array();',
);
foreach ($data as $identifier) {
$features_override_code[] = '';
$features_override_code[] = " // Exported overrides for: $identifier";
$features_override_code[] = ' $overrides[' . features_var_export($identifier) . '] = 1;';
}
// Create the default hook that defines all exported overrides.
$features_override_code[] = '';
$features_override_code[] = ' return $overrides;';
$list['features_override_default_items'] = implode("\n", $features_override_code);
*/
return $list;
}
/**
* Implements hook_features_export_render().
*/
function features_overrides_features_export_render($module, $data, $export = NULL) {
// Remember, the code exported here is just for the Features UI to keep track
// of the overridden status. All it needs to do is capture "changes".
// The actual form of the output doesn't really matter.
$list = $overrides_to_export = array();
// Go through all data collecting the items exports to create.
$features_override_code = array(
' // This code is only used for UI in features. Exported alters hooks do the magic.',
' $overrides = array();',
);
$last_component = '';
foreach ($data as $identifier) {
// Something is adding extra quote marks.
list($component, $element, $keys) = features_override_parse_identifier($identifier);
$component_code[$component] = isset($component_code[$component]) ? $component_code[$component] : array();
$overrides_to_export[$component] = isset($overrides_to_export[$component]) ? $overrides_to_export[$component] : array();
$overrides = features_override_get_overrides($component);
$features_override_value = array(
'additions' => array(),
'deletions' => array()
);
// Just specific keys are being exported so add them if set.
if (!empty($overrides[$element])) {
if (isset($overrides[$element]['additions'][$keys])) {
$overrides_to_export[$component][$element]['additions'][] = $overrides[$element]['additions'][$keys];
$features_override_value['additions'][] = $overrides[$element]['additions'][$keys];
}
elseif (isset($overrides[$element]['deletions'][$keys])) {
$overrides_to_export[$component][$element]['deletions'][] = $overrides[$element]['deletions'][$keys];
$features_override_value['deletions'][] = $overrides[$element]['deletions'][$keys];
}
}
if ($component != $last_component) {
$features_override_code[] = '';
$features_override_code[] = " // Exported overrides for: $component";
}
$last_component = $component;
if (count($features_override_value['additions'])) {
$features_override_code[] = ' $overrides["' . $identifier . '"] = ' . features_override_var_export($features_override_value['additions'][0]['value'], ' ') . ';';
}
else if (count($features_override_value['deletions'])) {
$features_override_code[] = ' $overrides["' . $identifier . '"]["DELETED"] = TRUE;';
}
}
// Create the default hook that defines all exported overrides.
$features_override_code[] = '';
$features_override_code[] = ' return $overrides;';
$list['features_override_default_overrides'] = implode("\n", $features_override_code);
$component_code = array();
foreach ($overrides_to_export as $component => $elements) {
foreach ($elements as $element => $overrides) {
$component_code[$component] = isset($component_code[$component]) ? $component_code[$component] : array();
$component_code[$component][] = ' if (isset($data[' . var_export($element,TRUE) . '])) {';
if (!empty($overrides['additions'])) {
foreach ($overrides['additions'] as $alter) {
$component_code[$component][] = implode("\n", features_override_features_export_render_addition($alter, $element, $component));
}
}
if (!empty($overrides['deletions'])) {
foreach ($overrides['deletions'] as $alter) {
$component_code[$component][] = implode("\n", features_override_features_export_render_deletion($alter, $element, $component));
}
}
$component_code[$component][] = ' }';
}
}
$info = features_get_components();
foreach ($component_code as $component => $code) {
$list[features_get_default_alter_hook($component) . '_alter'] = array(
'code' => implode("\n", $code),
'args' => '&$data',
'file' => 'features',
);
}
return $list;
}
/**
* Implements hook_features_revert().
*/
function features_override_items_features_revert($module) {
features_override_items_features_rebuild($module);
}
/**
* Implements of hook_features_rebuild().
*/
function features_override_items_features_rebuild($module) {
_features_override_features_rebuild($module, 'features_override_items');
}
/**
* Implements hook_features_revert().
*/
function features_overrides_features_revert($module) {
features_overrides_features_rebuild($module);
}
/**
* Implements of hook_features_rebuild().
*/
function features_overrides_features_rebuild($module) {
_features_override_features_rebuild($module, 'features_overrides');
}
/**
* Rebuilds fields from code defaults.
*
* FIXME This is reverting everything that has a change instead of this module.
*/
function _features_override_features_rebuild($module, $component_key = 'features_override_items') {
// first build list of components we are overriding
$parents = array();
$data = features_get_component_map();
foreach ($data[$component_key] as $identifier => $component_modules) {
list($component, $element) = features_override_parse_identifier($identifier);
if (isset($data[$component][$element])) {
foreach ($data[$component][$element] as $module_name) {
$parents[$module][$component] = $module_name;
}
}
}
// first, update get_default cache so rebuild will work on latest data
foreach ($parents as $module => $element) {
foreach ($element as $component) {
features_get_default($component, $module, TRUE, TRUE);
}
}
// rebuild those parent components
//features_rebuild($parents);
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* @file
* Contains implementation of features_override's hooks for other modules.
*/
/**
* Implements hook_features_override_component_overrides_alter().
*/
function image_features_override_component_overrides_alter(&$default, &$normal, $context) {
if ($context['component'] == 'image') {
// Effects have their keys changed on override. This resets them to numeric.
$normal['effects'] = array_values($normal['effects']);
$default['effects'] = array_values($default['effects']);
}
}
/**
* Implements hook_features_override_export_render_addition() for image.
*/
function image_features_override_export_render_addition($alter, $element) {
$code = array();
if (isset($alter['keys']) && isset($alter['value'])) {
$component_start = "\$data['$element']";
$code_line = features_override_export_keys($alter['keys']);
$value_export = features_override_var_export($alter['value'], ' ');
$code[] = "";
$code[] = " if (" . $component_start . "['storage'] == IMAGE_STORAGE_DEFAULT) {";
$code[] = " " . $component_start . $code_line . ' = ' . $value_export . ';';
$code[] = " }";
}
return $code;
}
/**
* Implements hook_features_override_export_render_addition() for image.
*/
function image_features_override_export_render_deletion($alter, $element) {
$code = array();
if (isset($alter['keys'])) {
$component_start = "\$data['$element']";
$code_line = features_override_export_keys($alter['keys']);
$code[] = "";
$code[] = " if (" . $component_start . "['storage'] == IMAGE_STORAGE_DEFAULT) {";
$code[] = ' unset(' . $component_start . $code_line . ');';
$code[] = " }";
}
return $code;
}

View File

@@ -0,0 +1,13 @@
name = Features Override
description = Allows exported Features to be overridden
core = 7.x
dependencies[] = ctools
dependencies[] = features
package = "Features"
; Information added by drupal.org packaging script on 2012-07-25
version = "7.x-2.0-beta1+3-dev"
core = "7.x"
project = "features_override"
datestamp = "1343175314"

View File

@@ -0,0 +1,126 @@
<?php
/**
* @file
* Module file for features overrides.
* Includes core/contrib hook implementations.
*/
// Key to use when marking properties for recursion.
define('FEATURES_OVERRIDE_RECURSION_MARKER', 'features_override_recursion_marker');
/**
* Implements hook_features_api().
*/
function features_override_features_api() {
$path = drupal_get_path('module', 'features_override') . '/features_override.features.inc';
return array(
'features_override_items' => array(
'name' => t('Feature Overrides'),
'default_hook' => 'features_override_default_items',
'default_file' => FEATURES_DEFAULTS_INCLUDED,
'feature_source' => TRUE,
'file' => $path,
),
'features_overrides' => array(
'name' => t('Feature Overrides (individual -- advanced)'),
'default_hook' => 'features_override_default_overrides',
'default_file' => FEATURES_DEFAULTS_INCLUDED,
'feature_source' => TRUE,
'file' => $path,
),
);
}
/**
* Implements hook_menu().
*/
function features_override_menu() {
$items = array();
$items['admin/structure/features/features_override'] = array(
'title' => 'Review Overrides',
'description' => 'Show override details for a component and element.',
'page callback' => 'features_override_render_differences',
'access callback' => 'user_access',
'access arguments' => array('administer features'),
'type' => MENU_LOCAL_TASK,
'file' => "features_override.admin.inc",
'weight' => 8,
);
return $items;
}
/**
* Implements hook_menu_alter
*/
function features_override_menu_alter(&$items) {
// override the existing "Review Overrides" tab
// do it here instead of hook_menu to ensure we run after features
$items['admin/structure/features/%feature/diff'] = array(
'title' => 'Review overrides',
'description' => 'Compare default and current feature.',
'page callback' => 'features_override_feature_diff',
'page arguments' => array(3, 5),
'load arguments' => array(3, TRUE),
'access callback' => 'features_access_override_actions',
'access arguments' => array(3),
'type' => MENU_LOCAL_TASK,
'file' => 'features_override.admin.inc',
'module' => 'features_override',
);
}
/**
* Implements hook_features_override_ignore().
*/
function features_override_features_override_ignore($component) {
// Determine which keys need to be ignored for override diff for various components.
// value is shows how many levels deep the key is
$ignores = array();
switch ($component) {
case 'views_view':
$ignores['current_display'] = 0;
$ignores['display_handler'] = 0;
$ignores['handler'] = 2;
$ignores['query'] = 0;
$ignores['localization_plugin'] = 0;
// Views automatically adds these two on export to set values.
$ignores['api_version'] = 0;
$ignores['disabled'] = 0;
break;
case 'image':
$ignores['module'] = 0;
$ignores['name'] = 0;
$ignores['storage'] = 0;
// Various properities are loaded into the effect in image_styles.
$ignores['summary theme'] = 2;
$ignores['module'] = 2;
$ignores['label'] = 2;
$ignores['help'] = 2;
$ignores['form callback'] = 2;
$ignores['effect callback'] = 2;
$ignores['dimensions callback'] = 2;
break;
case 'field':
$ignores['locked'] = 1;
break;
}
return $ignores;
}
/**
* Implements hook_modules_enabled().
*
* Revert the parent settings when the override module is enabled.
*/
function features_override_modules_enabled($modules) {
module_load_include('inc', 'features_override', 'features_override.features');
module_load_include('inc', 'features', 'features.export');
foreach ($modules as $module) {
if (function_exists($module . '_features_override_default')) {
features_override_features_rebuild($module);
}
}
}

View File

@@ -0,0 +1,57 @@
(function ($) {
Drupal.behaviors.features_override_form = {
attach: function(context, settings) {
$('#edit-sources-features-overrides:not(.features-override-processed)', context)
.prepend(Drupal.t('Advanced usage only. Allows you to select individual changes only to export.'))
.addClass('features-override-processed');
$('input[type=checkbox][name^="sources[features_override_items]"]:not(.features-override-form-processed)', context).each(function (i) {
var $parent_checkbox = $(this);
$parent_checkbox.addClass('features-override-form-processed');
var $parent_label = $parent_checkbox.parent().find('label');
// Create a link that links to the exact differences from the label.
if (Drupal.settings.features_override_links['main'][this.value]) {
$parent_label.append('<a href="' + Drupal.settings.features_override_links['main'][this.value] + '" target="_blank" class="features_override_button">' + Drupal.t('view') + '</a>');
}
var $child_checkboxes = $('input[type=checkbox][name^="sources[features_overrides]"][value^=' + this.value + ']').each(function (i) {
if (Drupal.settings.features_override_links['sub'][this.value]) {
$($(this).parent()).find('label').append('<a href="' + Drupal.settings.features_override_links['sub'][this.value] + '" target="_blank" class="features_override_button">' + Drupal.t('view') + '</a>');
}
}).parents('div.form-type-checkbox');
$child_checkboxes.wrapAll('<div class="features-override-children-wrapper" id="' + this.id + '-wrapper"></div>');
var $wrapper = $child_checkboxes.parent();
// Prepend a label saying what these overrides are for.
$wrapper.before('<h4>' + Drupal.t('Individual overrides for: ') + $parent_label.html() + '</h4>');
var fotext = Drupal.t('Full overrides already exported for this item to this feature.')
+ ' '
+ '<a href="#" id="' + this.id + '-refine" class="features_override_button">' + Drupal.t('refine') + '</a>';
$wrapper.after('<div class="features-override-children-warning" id="' + this.id + '-warning">' + fotext + '</div>');
// Unchecks the items component to allow indivudal refinment if desired.
$('#' + this.id + '-refine').bind('click', {id : this.id}, function(event) {
$('#' + event.data.id).removeAttr('checked').trigger('change');
return false;
});
// Disable child checkboxes when parent is selected
$parent_checkbox.change(function() {
features_override_switch_child_info(this.id, this.checked);
});
features_override_switch_child_info(this.id, this.checked);
});
}
}
function features_override_switch_child_info(id, is_checked) {
if (is_checked) {
// Jquery bug that hide() doesn't always work when parent hidden.
$('#' + id + '-wrapper').css('display', 'none');
$('#' + id + '-warning').css('display', 'block');
}
else {
$('#' + id + '-wrapper').show();
$('#' + id + '-warning').css('display', 'none');
}
}
})(jQuery);