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,104 @@
Skinr 7.x-2.x, xxxx-xx-xx
-------------------------
Issue #1299162 by nedjo: Added form callback functionality to skin plugins.
Fixed call by reference error.
Issue #1331004 by mrfelton: Fixed Undefined index: panels_pane() in
skinr_panels_preprocess_links().
Issue #1299162 by JurriaanRoelofs, moonray: Added form callback functionality to
skin plugins.
Issue #984402 by moonray: Updated Skinr admin UI.
Issue #952610 by aquariumtap, moonray | Alan D.: Added Vertical tabs integration.
Issue #1163618 by moonray: Fixed *.skinr.inc not auto-loading for certain hooks.
Issue #1163618 by moonray: Removed skinr_handlers and replaced them with proper
hooks.
Issue #1163618 by sun, moonray: Added dependency on panels for skinr_panels.
Issue #1163618 by sun, moonray: Fixed errors due to default groups not loaded
when clearing cache on Skin settings page.
Issue #1218786 by moonray: Fixed skinr_rule_is_visible() doesn't work properly
for node/add/[type] when limiting by content type.
Issue #1183954 by moonray: Fixed inability to register a skin under specific
theme hooks.
Issues #1127434 by moonray: Fixed previous widget displaying twice if skin type
is invalid in skin plugin.
Issue #1199972 by sun: Cleaned up tests.
by moonray: Organized testing related modules into their own sub-directories.
Issue #1185224 by moonray: Added tests for functionality plugins. Update.
Issue #1185224 by moonray: Added tests for functionality plugins. Fixed a small
inconsistency with panels plugin.
Issue #1044222 by sun, moonray: Removed left-over junk code.
Issue #1044222 by sun, moonray: Fixed tests.
Issue #1044222 by sun, moonray: Removed skin configuration functionality from
third-party forms.
by moonray: Fixed typo in skinr_get_config_info() that prevented skipping
re-loading of cached data.
#1148092 by moonray: Fixed PDOException on Skinr installation when using UTF8
character set in DB.
#891942 by Vraja, moonray: Tests for class lost when editing block and user doesn't
have "access skinr classes" permission. Bug already fixed by previous patch.
#1082842 by moonray: Update storage of skin configurations to give more
granular control.
#1050064 by moonray | Hari: Fixed Skinr failing to load CSS files when added at
the option level of a Skin.
#1053738 by moonray: Fixed Simpletest for Skinr UI fails.
#1051456 by moonray: Fixed $theme_registry() has no value in skinr_ui_preprocess().
#1040108 by sun, moonray: Fixed Default groups don't register.
#977118 by sun: Fixed Skins in disabled basetheme cannot be enabled for
basetheme (to appear in subtheme).
#1029058 by sun: Added first Skinr UI tests applying skin settings.
#1015614 by sun: Added tests ensuring skins of disabled themes aren't collected.
#1028334 by Jacine: Changed the 'default_status()" property to "default status".
#1015614 by Jacine: Fixing previous commit.
#1015614 by sun: Subtheme can collect skin information from disabled parent
themes.
#1015614 by sun, Jacine: Added normal themes (no skins) for testing purposes.
#1015614 by sun: Added a subtheme for testing.
#956994 by moonray, sun: Fixing an issue where JS and CSS files weren't loading
due to incorrect path information.
#1027294 by Jacine: Changed API Documentation.
#956994 by sun: Fixed plugin .inc files can be located in sub-directories.
#956994 by sun: Revert debugging code in skinr.test.
#956994 by sun, moonray, coltrane: Fixed Write load and parse code for Skinr
include files in PHP format.
#956932 and #956932 by Jacine, moonray, sun: Added new API documentation.
#977110 by moonray: Fixed typos in the default group implementation.
#995080 by Jacine: Fixed Permissions are confusing.
#956990 by sun: Renaming docs/docs.php to skinr.api.php.
#977110 by Jacine: Fixed Create the default group implementation.
#956990 by coltrane, Removed function_exists() call from
skinr_module_load_all_includes().
#995794 by coltrane, pillarsdotnet: Fixed Prevent 'invalid argument for
foreach()" error.
#999124 by sun, coltrane: Remove workaround due to fix in core issue #985578.
#999124 by coltrane: Fixed installation simpletest.
#995080 by moonray: Fixed admin/appearance/skinr/edit/%skinr_js()/%/% has wrong permission.
#948550 by moonray: Fixed a few views_object_cache() calls to use
ctools_object_cache_get().
#956990 by moonray: Fixing module_load_all_includes() which was broken by a
previous commit.
#956994 by jacine: Adding a Test skin module.
#956990 by moonray, sun: Round 2 of clean up in #956990.
#942950 by moonray, Jacine, sun: Fixed Rule creation form is broken and
confusing.
#956990 by moonray, sun: Changed function and variable names to follow Drupal
core.
#957070 by moonray, sun: Fixed code documentation.
#957388 by Jacine, sun, Jeff Burnz: Fixed theme_skinr_ui_filters() still uses
dl.multiselect markup/styling.
#948550 by nomonstersinme, moonray: Updated Views integration for 7.x.
#960548 by moonray, Vraja, Jacine: Removed support for template files.
#906764 by Vraja, DamienMcKenna: Fixed logic error in skinr_submit_handler().
#796780 by moonray, sun, ericduran, neochief: Fixed problems with other modules
during hook_init().
#949746 by sun, nomonstersinme: Fixed Skins page broken.
#947790 by moonray, Jacine: Updated Panels integration for 7.x.
#954874 by moonray, sun: Removed .info file handling.
#943064 by moonray, Jacine: Fixed rules settings fieldset for region editing.
#947738 by moonray, nomonstersinme: Fixed region handling for skins.
#945086 by yettyn, ezra-g: Fixed PDOException in skinr_update_7002().
#908946 by sun: Fixed hook_menu() is invoked for disabled modules.
#908946 by sun: Fixed module update functions.
#943008 by moonray: Fixed block_skinr_preprocess_hook_callback() never returning
alternate block hooks.
#942292 by Jacine: Added Advanced Help support files.
#917540 by Jacine: Added support for Form API #weight attribute.
#908946 by sun: Partial clean up of Drupal 7 port.

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,40 @@
-- SUMMARY --
Please refer to the following for documentation:
Introduction: http://drupal.org/node/578552
Documentation: http://drupal.org/node/578574
For a full description of the module, visit the project page:
http://drupal.org/project/skinr
To submit bug reports and feature suggestions, or to track changes:
http://drupal.org/project/issues/skinr
-- REQUIREMENTS --
* @todo Basically, you need nothing, but then again, you need skins.
-- INSTALLATION --
* Install as usual, see http://drupal.org/node/70151 for further information.
-- CONFIGURATION --
-- CUSTOMIZATION --
-- FAQ --
-- CONTACT --
Current maintainers:
* Balarama Bosch (moonray) - http://drupal.org/user/68275
* Jacine Luisi (Jacine) - http://drupal.org/user/88931

View File

@@ -0,0 +1,49 @@
<h3>Base themes</h3>
<ul>
<li><a href="http://drupal.org/project/adaptivetheme">Adaptive Theme</a></li>
<li><a href="http://drupal.org/project/basic">Basic</a></li>
<li><a href="http://drupal.org/project/blueprint">Blueprint</a></li>
<li><a href="http://drupal.org/project/fusion">Fusion</a></li>
<li><a href="http://drupal.org/project/Hexagon">Hexagon</a></li>
<li><a href="http://drupal.org/project/studio">Studio</a></li>
<li><a href="http://drupal.org/project/zen">Zen</a></li>
</ul>
<h3>General/Subthemes</h3>
<ul>
<li><a href="http://drupal.org/project/abstract">Abstract</a></li>
<li><a href="http://drupal.org/project/acquia_prosper">Acquia Prosper</a></li>
<li><a href="http://drupal.org/project/acquia_slate">Acquia Slate</a></li>
<li><a href="http://drupal.org/project/at_koda">AT Koda</a></li>
<li><a href="http://drupal.org/project/at_panels_everywhere">AT Panels Everywhere</a></li>
<li><a href="http://drupal.org/project/celadon">Celadon</a></li>
<li><a href="http://drupal.org/project/lightfantastic">Light Fantastic</a></li>
<li><a href="http://drupal.org/project/magazeen">Magazeen</a></li>
<li><a href="http://drupal.org/project/newswire">Newswire</a></li>
<li><a href="http://drupal.org/project/orange">Orange</a></li>
<li><a href="http://drupal.org/project/simply_modern">Simple Modern</a></li>
</ul>
<h3>Commercial Themes</h3>
<ul>
<li><a href="http://pixeljets.com/drupal-themes/aura">Aura</a></li>
<li><a href="http://www.sooperthemes.com/drupal-themes/aureus">Aureus</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/bubblr">Bubblr</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/clean-commerce">Clean Commerce</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/copywrite">Copywrite</a></li>
<li><a href="http://www.sooperthemes.com/drupal-themes/cuttingedge">Cuttingedge</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/early-edition">Early Edition</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/fresh-start">Fresh Start</a></li>
<li><a href="http://www.sooperthemes.com/drupal-themes/galaxy">Galaxy</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/grunge">Grunge</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/lockdown">Lockdown</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/luxe">Luxe</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/market-share">Market Share</a></li>
<li><a href="http://www.sooperthemes.com/drupal-themes/new-media">New Media</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/pump-volume">Pump Up The Volume</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/sharp-sales">Sharp Sales</a></li>
<li><a href="http://www.sooperthemes.com/drupal-themes/syan">Syan</a></li>
<li><a href="http://www.sooperthemes.com/drupal-themes/synopsis">Synopsis</a></li>
<li><a href="http://pixeljets.com/drupal-themes/taurine">Taurine</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/technoli">Technoli</a></li>
<li><a href="http://fusiondrupalthemes.com/theme/tranquil">Tranquil</a></li>
<li><a href="http://www.sooperthemes.com/drupal-themes/urgency">Urgency</a></li>
</ul>

View File

@@ -0,0 +1,36 @@
<h3>Reporting issues/bugs</h3>
<p>Before <a href="http://drupal.org/node/add/project-issue/skinr">creating a
new issue</a>, please make sure to <a
href="http://drupal.org/project/issues/search/skinr">search existing
issues</a> first to see if your problem has already been reported. Remember to
include as much information as possible about the issue your are experiencing,
the setup you are running, and anything else that would be helpful for us to
reproduce the issue.
</p>
<h3>Providing patches</h3>
<p>We love patches. If you are looking to submit a patch or have an idea for a
new feature, we'd love to hear from you. Please start by:</p>
<ol>
<li><a href="http://drupal.org/coding-standards">Coding Standards</a></li>
<li><a href="http://drupal.org/patch/create">Learn how to create
patches</a></li>
<li><a href="http://drupal.org/node/add/project-issue/skinr">Create an
issue</a></li>
</ol>
<h3>Sharing your work with others</h3>
<p>If you've created a nice menu, block, tab style, or whatever, please consider
packaging it up, and sharing it with the community. Your contribution could
really help out someone new. If you have a skin to share, please post it to
the <a href="http://drupal.org/project/issues/skinr">Skinr project issue
queue</a>. Also note, you do not have to contribute code. If you are a
designer, feel free to submit mockups!
</p>
<h3>Showing off your work</h3>
<p>We love to see how people are using Skinr. If you have done something cool
with Skinr, and want to tell us about it, please post to the <a
href="http://drupal.org/project/issues/skinr">Skinr project issue
queue</a>.
</p>

View File

@@ -0,0 +1,68 @@
<p>The main advantage of using Skinr is that it provides a means of easily
reusing CSS classes. How you set up those classes and the code you provide
is up to you. This page is meant to inform you about your options.
</p>
<h3 id="css-js-classes">CSS classes in Skins</h3>
<p>Classes in Skinr are typically defined in the <a
href="topic:skinr/syntax#syntax-options">skin options</a>. A single class is
all that is necessary, but multiple classes can easily be added.
</p>
<h4 id="css-js-classes-single">Single Class</h4>
<pre>skinr[skin_system_name][options][1][class] = foo-class</pre>
<h4 id="css-js-classes-multiple">Multiple Classses</h4>
<p>Multiple classes should be separated by a single space.</p>
<pre>skinr[skin_system_name][options][1][class] = foo-class bar-class</pre>
<h3 id="css-js-external">External CSS &amp; JavaScript files</h3>
<p>CSS can be stored in external files, or the files can simply be added to
your theme's existing CSS file. Personally, I like to create a separate CSS
file that stores the bulk of Skinr CSS. The same can be done with JavaScript
files. If your skins require CSS &amp; Javascript that is used site wide, the
best approach is to load the files normally via the theme. This will ensure
your files are loaded on all pages and therefore always available.</p>
<pre>
stylesheets[all][] = css/skinr.css
scripts[] = js/skinr.js
</pre>
<h4>Adding files to skins</h4>
<p>There are cases where it makes sense to handle loading the CSS/JavaScript
files in the skin itself. This can be done by by adding the following line(s)
to your skin.
</p>
<pre>
skinr[skin_system_name][scripts][] = css/dropdown.js
skinr[skin_system_name][stylesheets][all][] = css/dropdown.css
</pre>
<h4>Adding files to skin options</h4>
<p>This can be taken a step further by including files per option. Below is a
detailed example of what a use case for this might look like:</p>
<pre>
skinr[dropdowns][title] = Dropdown Menus
skinr[dropdowns][type] = select
skinr[dropdowns][description] = Select a vertical or horizontal dropdown menu.
skinr[dropdowns][features][] = block_menu_block
skinr[dropdowns][stylesheets][all][] = css/dropdown.css
skinr[dropdowns][scripts][] = js/hoverIntent.js
skinr[dropdowns][options][1][label] = Horizontal
skinr[dropdowns][options][1][class] = dd-vertical
skinr[dropdowns][options][1][stylesheets][all][] = css/dropdown-vertical.css
skinr[dropdowns][options][1][scripts][] = js/dropdown-vertical.js
skinr[dropdowns][options][2][label] = Vertical
skinr[dropdowns][options][2][class] = dd-horizontal
skinr[dropdowns][options][2][stylesheets][all][] = css/dropdown-horizontal.css
skinr[dropdowns][options][2][scripts][] = js/dropdown-horizontal.js
</pre>
<p>The syntax for adding these files is the same as Drupal. See <a
href="http://drupal.org/node/171205">Structure of the .info file</a> for full
details.</p>
<h3 id="css-js-ui-classes">Defining classes in the UI</h3>
<p>In addition to defining CSS classes in the .info file, you can also add
classes directly into the UI. Under "Advanced Options" there is a text field
where you can add a class or classes manually. The syntax for adding classes
the same as the <a href="#css-js-classes">above examples</a>, with multiple classes separated by a space.
</p>
<p><img src="&path&images/ui-e.png" alt="Adding classes in the UI" /></p>

View File

@@ -0,0 +1,56 @@
<p>Below are some quick side-by-side comparisons of basic Skinr syntax and
what they translate to in the UI.</p>
<dl>
<dt>
<h4>Single</h4>
</dt>
<dd>
<pre>
skinr[example_single][title] = Single
skinr[example_single][description] = A skin with a single option.
skinr[example_single][options][1][label] = Foo
skinr[example_single][options][1][class] = foo-class</pre>
<img src="&path&images/ui-a.png" alt="Single Example" />
</dd>
<dt>
<h4>Multiple</h4>
</dt>
<dd>
<pre>
skinr[example_multiple][title] = Multiple (checkboxes)
skinr[example_multiple][description] = A skin multiple options that uses a <strong>checkboxes</strong> (multiple choices).
skinr[example_multiple][options][1][label] = Foo
skinr[example_multiple][options][1][class] = foo-class
skinr[example_multiple][options][2][label] = Bar
skinr[example_multiple][options][2][class] = bar-class</pre>
<img src="&path&images/ui-b.png" alt="Multiple (checkboxes)" />
</dd>
<dt>
<h4>Multiple (radios)</h4>
</dt>
<dd>
<pre>
skinr[example_multiple_radio][title] = Multiple (radios)
skinr[example_multiple_radio][type] = radios
skinr[example_multiple_radio][description] = A skin multiple options that uses <strong>radios</strong> (single choice).
skinr[example_multiple_radio][options][1][label] = Foo
skinr[example_multiple_radio][options][1][class] = foo-class
skinr[example_multiple_radio][options][2][label] = Bar
skinr[example_multiple_radio][options][2][class] = bar-class</pre>
<img src="&path&images/ui-c.png" alt="Multiple (radios)" />
</dd>
<dt>
<h4>Multiple (select)</h4>
</dt>
<dd>
<pre>
skinr[example_multiple_radio][title] = Multiple (select)
skinr[example_multiple_radio][type] = select
skinr[example_multiple_radio][description] = A skin multiple options that uses <strong>radios</strong> (single choice).
skinr[example_multiple_radio][options][1][label] = Foo
skinr[example_multiple_radio][options][1][class] = foo-class
skinr[example_multiple_radio][options][2][label] = Bar
skinr[example_multiple_radio][options][2][class] = bar-class</pre>
<img src="&path&images/ui-d.png" alt="Multiple (select)" />
</dd>
</dl>

View File

@@ -0,0 +1,53 @@
<p><code>[features]</code> are an optional Skinr setting. They do not need to be
specified. By default Skinr will assume that your styles can be used anywhere
Skinr is available on your site, i.e. nodes, blocks, etc. If you want to
reduce UI clutter and have more fine grained control over where your skins are
used, you'll want to use the <code>[features]</code> option.
</p>
<p>The <code>[features]</code> setting is the equivalent of the high level
Drupal theme hook. If nothing is specified in your skin it will appear
everywhere by default. It may only contain underscores. By specifying a
<code>[features]</code> you are telling Skinr: Only show this skin when
editing X.
</p>
<p>Below is a listing of available options, by module:</p>
<h3>Blocks</h3>
<pre>
skinr[skin_system_name][features][] = block
skinr[skin_system_name][features][] = block_[module]
</pre>
<h3>Comments</h3>
<pre>
skinr[skin_system_name][features][] = comment_wrapper
skinr[skin_system_name][features][] = comment_wrapper_[node_type]
</pre>
<h3>Nodes</h3>
<pre>
skinr[skin_system_name][features][] = node
skinr[skin_system_name][features][] = node_[node_type]
</pre>
<em class="marker">Note: node_[node_type] is not yet implemented.</em>
<h3>Page (body classes)</h3>
<pre>
skinr[skin_system_name][features][] = page
</pre>
<h3>Panels</h3>
<pre>
skinr[skin_system_name][features][] = panels_pane
skinr[skin_system_name][features][] = panels_panel
</pre>
<h3>Views</h3>
<pre>
skinr[skin_system_name][features][] = views_view
skinr[skin_system_name][features][] = views_view__[style_name]
skinr[skin_system_name][features][] = views_view__[display_name]
skinr[skin_system_name][features][] = views_view__[view_name]
skinr[skin_system_name][features][] = views_view__[view_name]__[display_name]
</pre>
<em class="marker">Note: views_view__[style_name] is not yet implemented.</em>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,3 @@
If you are creating a subtheme and the base theme you are using contains it's own Skinr styles, Skinr allows you to choose whether or not you want your subtheme to inherit those skins or not. By default Skinr will NOT inherit skins. If you want to be able to use a base theme's skins, you will need to add this line to your .info file.
<pre>skinr[options][inherit_skins] = true</pre>

View File

@@ -0,0 +1,63 @@
<p>
While skins can be provided in a theme, doing so has the potential
disadvantage of making the skin available only to users of that theme (or
themes based off of it). Many skins may be useful in any theme, or may provide
building blocks that a particular theme could customize. When producing skins,
please consider first whether you can make your work generic enough to provide
in a module, thereby making it available to all Drupal users.
</p>
<p>The good news is that providing a skin in a module rather than a theme is
quick and easy, even if you've never used PHP. In the steps below, we outline
how to create a module for your skins. When creating your module, simply
substitute occurrences of "block_skins" with a "machine name" (a name suitable
for computers to read) of your choosing and change the description accordingly.
Drupal module names typically are all lower case with no spaces and no
punctuation except underscores (which are used to separate words).
</p>
<ol>
<li>
<p>Create a new folder in your modules directory using the machine name:</p>
<pre>sites/all/modules/block_skins</pre>
</li>
<li>
<p>
Create a <code>block_skins.info</code> file inside the
<code>block_skins</code> folder and include following code inside the
file:
</p>
<pre>
name = "Block Skins"
description = "A set of skins providing configurable layout options for blocks."
package = "Skinr"
core = 6.x</pre>
</li>
<li>
<p>
Create a <code>block_skins.module</code> file inside the
<code>block_skins</code> folder and include the following code inside the
file:
</p>
<pre>
&lt;?php
/**
* Implementation of hook_skinr_api().
*/
function block_skins_skinr_api() {
return array(
'api' => 1,
'path' => drupal_get_path('module', 'block_skins'),
'skins' => TRUE,
);
}</pre>
<li>
<p>
Put your skins in a folder called <code>skins</code> inside your module's
folder.
</p>
</li>
</ol>
<p>
And that's it! You're ready to use and contribute your module, just like you
would a theme. See the Drupal handbook documentation on
<a href="http://drupal.org/node/7765">maintaining a project on drupal.org</a>.
</p>

View File

@@ -0,0 +1,12 @@
<p><a href="http://drupal.org/project/skinr">Skinr's</a> main purpose is to allow the theme to define a set of reusable and modular CSS styles, and to make those styles available in Drupal's UI . Skinr was developed for themers to allow them to tap into the power of Drupal's modularity and apply those same principals to theme development. It does not provide any styles of its own. These styles are defined in the .info file of the theme (or subtheme), by the themer and end up in various places in Drupal's UI, such as:</p>
<ul>
<li>Block Configuration</li>
<li>Node Type (and Comment) Configuration</li>
<li><a href="http://drupal.org/project/panels">Panel</a> Panes</li>
<li><a href="http://drupal.org/project/views">Views</a> Displays</li>
</ul>
<p>One important thing to note is that Skinr is really just a tool. It can be used for different purposes, i.e. a contrib theme, or client theme. Both serve very different purposes and should probably be approached differently with the end user and overall project goals in mind. Using it to its full potential is really up to you.</p>
<p>If you are looking to implement Skinr on one of your projects, I highly recommend planning it out at the very beginning of the project. Converting an existing theme to use Skinr is generally not recommended if you are under time constraints, UNLESS it is a contributed theme.</p>

View File

@@ -0,0 +1,6 @@
<p><a href="/admin/build/skinr/page">Page rules</a> allow you to use Skinr to
add body classes to your page(s) based on user role, path, or PHP code, just
like block visibility settings. They can be used to do things like: set a
container width for grids, define sections of a site, change font size/face,
background colors, etc.
</p>

View File

@@ -0,0 +1,46 @@
[overview]
title = "Overview"
weight = 0
[syntax]
title = "Syntax"
weight = 1
[css-js]
title = "CSS, Stylesheets & JavaScript"
parent = syntax
weight = 1
[features]
title = "Features"
parent = syntax
weight = 2
[examples]
title = "Examples"
parent = syntax
weight = 6
[rules]
title = "Page Rules"
weight = 2
[inheritance]
title = "Inheriting Skins from Base Themes"
weight = 3
[modules]
title = "Providing skins in a module"
weight = 4
[theme]
title = "Making Skinr work with your theme"
weight = 5
[contrib-themes]
title = "Themes that support Skinr natively"
weight = 6
[contribute]
title = "Contribute"
weight = 7

View File

@@ -0,0 +1,116 @@
<p>These are the basic building blocks of a Skin. If you are already familiar
with this, you might want to see some quick <a href="topic:skinr/examples">examples</a>.</p>
<dl>
<dt>
<h3 id="syntax-machine-name">Machine Name</h3>
</dt>
<dd>
<p>Each skin begins with the prefix <code>skinr</code> in your .info file.
This allows Drupal and Skinr to easily identify and access information
about your skins. It will not show up in the UI or in any markup.
</p>
<pre>skinr[skin_system_name]</pre>
</dd>
<dt>
<h3 id="syntax-title">Title</h3>
</dt>
<dd>
<p>Every skin has one title. This title will appear in the UI as the form
element label, so it should be descriptive of what the Skin is/does.
</p>
<pre>skinr[skin_system_name][title] = Example</pre>
</dd>
<dt>
<h3 id="syntax-description">Description</h3>
</dt>
<dd>
<p>Descriptions are optional, but recommended. They will show in the UI just
as regular form item descriptions do. They may contain HTML.
</p>
<pre>skinr[skin_system_name][description] = This should be a description of my Skin.</pre>
</dd>
<dt>
<h3 id="syntax-type">Type</h3>
</dt>
<dd>
<p>There are 3 different options for displaying your Skinr styles in the UI.
These <strong>types</strong> correspond to Drupal's form API widgets. They
were created to allow you to better present your skins in the UI and to
allow fine-grained control over the options you provide.
</p>
<ol>
<li>
<p><em>checkboxes (default)</em> &ndash; Can be used for singular or
multiple options. Do not use "checkbox" as it will not work. Also
note: Skinr applies checkboxes by default, so it's not necessary to
specify if that's what you want to use.
</p>
<pre>skinr[skin_system_name][type] = checkboxes</pre>
</li>
<li>
<p><em>select</em> &ndash; Good for presenting many options when only
one can be selected. Note: multiple selects are not supported;
checkboxes should be used instead.
</p>
<pre>skinr[skin_system_name][type] = select</pre>
</li>
<li>
<p><em>radios</em> &ndash; Can be used for single options.</p>
<pre>skinr[skin_system_name][type] = radios</pre>
</li>
</ol>
</dd>
<dt>
<h3 id="syntax-options">Options</h3>
</dt>
<dd>
<p>After deciding upon a widget type, you'll need to define your
options. You'll always need to have at least one option. Each option is
keyed, and consists of both a label and a class. The label will appear in
the UI and the class is the CSS class(es) you want to use. See <a
href="topic:skinr/css">CSS</a> for more information.
</p>
<h4 id="syntax-options-singular">Singular</h4>
<pre>
skinr[skin_system_name][options][1][label] = Foo
skinr[skin_system_name][options][1][class] = foo-class</pre>
<h4 id="syntax-options-multiple">Multiple</h4>
<p><em>Note:</em> Skinr will include a <code>&lt;none&gt;</code> option
automatically for skins that have multiple options so the skin can be
unselected by the user.</p>
<pre>
skinr[skin_system_name][options][1][label] = Foo
skinr[skin_system_name][options][1][class] = foo-class
skinr[skin_system_name][options][2][label] = Bar
skinr[skin_system_name][options][2][class] = bar-class</pre>
<h4>Adding files</h4>
<p>More information on adding files can be found <a href="topic:skinr/css-js">here</a>, but a brief overview of the syntax is below.
</p>
<pre>
skinr[skin_system_name][options][1][stylesheets][all][] = foo.css
skinr[skin_system_name][options][1][scripts][] = foo.js</pre>
</dd>
<dt>
<h3 id="syntax-groups">Groups</h3>
</dt>
<dd>
<p>Groups allow you to place skins inside a fieldset. This is useful when
trying to present a bunch of related Skins. You may also choose to show
the fieldset as collapsed by default.
</p>
<h4 id="syntax-group">Defining a group</h4>
<pre>
skinr[options][groups][skin_group_name][title] = Example Group
skinr[options][groups][skin_group_name][description] = Set font-family and size options.
skinr[options][groups][skin_group_name][collapsible] = 1 // Defaults to 1. Options are 1 or 0.
skinr[options][groups][skin_group_name][collapsed] = 0 // // Defaults to 0. Options are 1 or 0.
</pre>
<h4 id="syntax-group-skin">Associating a skin with a group</h4>
<pre>
skinr[skin_name][title] = Example Skin
skinr[skin_name][description] = This should be a description of my Skin.
skinr[skin_name][group] = skin_group_name
...</pre>
</dd>
</dl>

View File

@@ -0,0 +1,38 @@
<p>Skinr creates a variable containing your skins class that you need to print
inside your template files. Thankfully this will not be necessary in Drupal 7,
but for now you'll need to add the <code>$skinr</code> variable and all the
template files you plan to use yourself.
</p>
<h3>Printing the $skinr variable</h3>
<p>The <code>$skinr</code> variable should be printed in the class attribute of
the first, or outer-most <code>&lt;div&gt;</code> in your theme's template
files. The variable is the same no matter which type you are dealing with, but
you may need to add template files to your theme. The variable is added by
doing:
</p>
<pre>&lt;?php print $skinr; ?&gt;</pre>
<p>NOTE: Depending on how your template files are structured, you may need to add a blank space before the variable so it doesn't conflict with other classes you might have:</p>
<pre>&lt;?php print ' '. $skinr; ?&gt;</pre>
<h3>Template files needed in your theme</h3>
<p>Here is a list of template files that are typically used and supported by
Skinr. See the link for each if you need to create these from scratch in your
theme. These links point to Drupal's default code for the template files.
You'll be able to copy/paste that code or tpl file to your theme. Then you can
add the <code>$skinr</code> variable and modify the code to suit your needs.
</p>
<ul>
<li><a href="http://api.drupal.org/api/drupal/modules--system--block.tpl.php/6/source">block.tpl.php</a></li>
<li><a href="http://api.drupal.org/api/drupal/modules--node--node.tpl.php/6/source">node.tpl.php</a></li>
<li><a href="http://api.drupal.org/api/drupal/modules--comment--comment-wrapper.tpl.php/6/source">comment-wrapper.tpl.php</a></li>
<li><a href="http://drupalcode.org/viewvc/drupal/contributions/modules/views/theme/views-view.tpl.php?view=markup">views-view.tpl.php</a></li>
<li><a href="http://drupalcode.org/viewvc/drupal/contributions/modules/panels/templates/panels-pane.tpl.php?view=markup">panels-pane.tpl.php</a></li>
</ul>
<p>Note: If you have other template files, i.e. node-blog.tpl.php make sure you print the <code>$skinr</code> variable in them, otherwise it wont work.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

View File

@@ -0,0 +1,180 @@
(function ($) {
// Make sure our objects are defined.
Drupal.CTools = Drupal.CTools || {};
Drupal.Skinr = Drupal.Skinr || {};
Drupal.Skinr.editUrl = 'admin/settings/skinr/edit/nojs';
Drupal.Skinr.infoUrl = 'admin/settings/skinr/info';
Drupal.behaviors.Skinr = {
attach: function(context, settings) {
for (var i in settings.skinr['areas']) {
var $module = settings.skinr['areas'][i]['module'];
var $elements = settings.skinr['areas'][i]['elements'];
var $id = settings.skinr['areas'][i]['id'];
var $region = $('.skinr-id-' + $id).once('skinr-region', function() {});
if (settings.skinr['areas'][i]['classes'] == undefined) {
settings.skinr['areas'][i]['classes'] = $($region).attr('class');
}
if ($region.length > 0) {
var $links = '';
for (var $j in $elements) {
var $classes = '';
if ($j == 0) {
$classes += ' first';
}
if ($j == $elements.length - 1) {
$classes += ' last';
}
if ($elements.length > 1) {
$links += '<li class="skinr-link-' + $j + $classes + '"><a href="' + settings.basePath + Drupal.Skinr.editUrl + '/' + $module + '/' + $elements[$j] + '/' + $elements +'" class="skinr-link ctools-use-dialog">' + Drupal.t('Edit skin') + ' ' + (parseInt($j) + 1) + '</a></li>';
}
else {
$links = '<li class="skinr-link-0 first last"><a href="' + settings.basePath + Drupal.Skinr.editUrl + '/' + $module + '/' + $elements[$j] +'" class="skinr-link ctools-use-dialog">' + Drupal.t('Edit skin') + '</a></li>';
}
}
var $wrapper_classes = '';
if ($module == 'page') {
$wrapper_classes += ' skinr-links-wrapper-page';
}
$region.prepend('<div class="skinr-links-wrapper' + $wrapper_classes + '"><ul class="skinr-links">' + $links + '</ul></div>');
$region.get(0).skinr = { 'module': $module, 'elements': $elements, 'id': $id };
Drupal.behaviors.Dialog($region);
};
}
$('div.skinr-links-wrapper', context).once('skinr-links-wrapper', function () {
var $wrapper = $(this);
var $region = $wrapper.closest('.skinr-region');
var $links = $wrapper.find('ul.skinr-links');
var $trigger = $('<a class="skinr-links-trigger" href="#" />').text(Drupal.t('Configure')).click(
function () {
$wrapper.find('ul.skinr-links').stop(true, true).slideToggle(100);
$wrapper.toggleClass('skinr-links-active');
return false;
}
);
// Attach hover behavior to trigger and ul.skinr-links.
$trigger.add($links).hover(
function () { $region.addClass('skinr-region-active'); },
function () { $region.removeClass('skinr-region-active'); }
);
// Hide the contextual links when user rolls out of the .skinr-links-region.
$region.bind('mouseleave', Drupal.Skinr.hideLinks).click(Drupal.Skinr.hideLinks);
// Prepend the trigger.
$links.end().prepend($trigger);
});
// Add a close handler to the dialog.
if (Drupal.Dialog.dialog && !Drupal.Dialog.dialog.hasClass('skinr-dialog-processed')) {
Drupal.Dialog.dialog.addClass('skinr-dialog-processed').bind('dialogbeforeclose', function(event, ui) {
// Reset all the applied style changes.
for (var i in Drupal.settings.skinr['areas']) {
var $id = Drupal.settings.skinr['areas'][i]['id'];
var $classes = Drupal.settings.skinr['areas'][i]['classes'];
$('.skinr-id-' + $id).attr('class', $classes);
}
});
}
}
}
/**
* Disables outline for the region contextual links are associated with.
*/
Drupal.Skinr.hideLinks = function () {
$(this).closest('.skinr-region')
.find('.skinr-links-active').removeClass('skinr-links-active')
.find('ul.skinr-links').hide();
};
Drupal.behaviors.SkinrLivePreview = {
attach: function(context, settings) {
$('#skinr-ui-form .skinr-ui-current-theme :input:not(.skinr-live-preview-processed)', context).addClass('skinr-live-preview-processed').change(function () {
var $tag = $(this).attr('tagName');
$tag = $tag.toLowerCase();
var $module = $('#skinr-ui-form #edit-module').val();
var $element = $('#skinr-ui-form #edit-element').val();
var $elements = $('#skinr-ui-form #edit-elements').val();
if (!$elements) {
$elements = $element;
}
var $name = $(this).attr('name');
$name = $name.replace(/skinr_settings\[.*_group\]\[[^\]]*\]\[([^\]]*)\]/, '$1');
var $classes = '';
var $add_classes = $(this).val();
if ($tag == 'select') {
$(this).find('option').each(function() {
$classes += ' ' + $(this).attr('value');
});
}
else if ($tag == 'input') {
}
// Use AJAX to grab the CSS and JS filename.
$.ajax({
type: 'GET',
dataType: 'json',
url: Drupal.settings.basePath + Drupal.Skinr.infoUrl + '/' + $name + '/' + $add_classes,
success: function($data) {
var $command = {
command: 'skinrAfterupdate',
module: $module,
elements: $elements,
classes: {
remove: $classes,
add: $add_classes
},
css: $data.css,
js: $data.js,
nosave: true
};
Drupal.CTools.AJAX.commands.skinrAfterupdate($command);
}
});
});
}
}
/**
* AJAX responder command to dismiss the modal.
*/
Drupal.CTools.AJAX.commands.skinrAfterupdate = function(command) {
if (command.module && command.elements && (command.classes.remove || command.classes.add)) {
if (command.css) {
for (var j in command.css) {
$(document.createElement('link')).attr({href: Drupal.settings.basePath + command.css[j].path, media: command.css[j].media, rel: 'stylesheet', type: 'text/css'}).appendTo('head');
}
}
if (command.js) {
for (var j in command.js) {
$.getScript(Drupal.settings.basePath + command.js[j].path);
}
}
for (var i in Drupal.settings.skinr['areas']) {
if (Drupal.settings.skinr['areas'][i]['module'] == command.module && Drupal.settings.skinr['areas'][i]['elements'] == command.elements) {
$('.skinr-id-' + Drupal.settings.skinr['areas'][i]['id']).removeClass(command.classes.remove).addClass(command.classes.add);
if (command.nosave == undefined || command.nosave == false) {
Drupal.settings.skinr['areas'][i]['classes'] = $('.skinr-id-' + Drupal.settings.skinr['areas'][i]['id']).attr('class');
}
}
}
}
}
})(jQuery);

View File

@@ -0,0 +1,59 @@
// $Id$
(function ($) {
/**
* Provide the summary information for the block settings vertical tabs.
*/
Drupal.behaviors.skinrUIRuleSettingsSummary = {
attach: function (context) {
// The drupalSetSummary method required for this behavior is not available
// on the Blocks administration page, so we need to make sure this
// behavior is processed only if drupalSetSummary is defined.
if (typeof jQuery.fn.drupalSetSummary == 'undefined') {
return;
}
$('fieldset#edit-path', context).drupalSetSummary(function (context) {
if (!$('textarea[name="pages"]', context).val()) {
return Drupal.t('Not restricted');
}
else {
return Drupal.t('Restricted to certain pages');
}
});
$('fieldset#edit-node-type', context).drupalSetSummary(function (context) {
var vals = [];
$('input[type="checkbox"]:checked', context).each(function () {
vals.push($.trim($(this).next('label').text()));
});
if (!vals.length) {
vals.push(Drupal.t('Not restricted'));
}
return vals.join(', ');
});
$('fieldset#edit-role', context).drupalSetSummary(function (context) {
var vals = [];
$('input[type="checkbox"]:checked', context).each(function () {
vals.push($.trim($(this).next('label').text()));
});
if (!vals.length) {
vals.push(Drupal.t('Not restricted'));
}
return vals.join(', ');
});
$('fieldset#edit-user', context).drupalSetSummary(function (context) {
var $radio = $('input[name="custom"]:checked', context);
if ($radio.val() == 0) {
return Drupal.t('Not customizable');
}
else {
return $radio.next('label').text();
}
});
}
};
})(jQuery);

View File

@@ -0,0 +1,47 @@
<?php
/**
* @file
* Implements Skinr hooks for block.module.
*/
/**
* Implements hook_skinr_config_info().
*/
function block_skinr_config_info() {
return array('block');
}
/**
* Implements hook_skinr_theme_hooks().
*/
function block_skinr_theme_hooks($module, $element) {
$theme_hooks = array();
if ($module == 'block') {
list($module, $delta) = explode('__', $element, 2);
$result = db_select('block', 'b')
->fields('b')
->distinct()
->condition('b.module', $module)
->condition('b.delta', $delta)
->range(0, 1)
->execute();
foreach ($result as $block) {
$theme_hooks[] = 'block__'. $block->module;
}
$theme_hooks[] = 'block';
}
return $theme_hooks;
}
/**
* Implements hook_skinr_elements().
*/
function block_skinr_elements($variables, $hook) {
$elements = array();
if ($hook == 'block') {
$elements['block'] = array($variables['block']->module . '__' . $variables['block']->delta);
}
return $elements;
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* @file
* Implements Skinr hooks for comment.module.
*/
/**
* Implements hook_skinr_config_info().
*/
function comment_skinr_config_info() {
return array('comment');
}
/**
* Implements hook_skinr_theme_hooks().
*/
function comment_skinr_theme_hooks($module, $element) {
$theme_hooks = array();
if ($module == 'comment') {
$theme_hooks = array(
'comment_wrapper__' . $element,
'comment_wrapper',
);
}
return $theme_hooks;
}
/**
* Implements hook_skinr_elements().
*/
function comment_skinr_elements($variables, $hook) {
$elements = array();
if ($hook == 'comment_wrapper') {
$elements['comment'] = array($variables['node']->type);
}
return $elements;
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* @file
* Implements Skinr hooks for node.module.
*/
/**
* Implements hook_skinr_config_info().
*/
function node_skinr_config_info() {
return array('node');
}
/**
* Implements hook_skinr_theme_hooks().
*/
function node_skinr_theme_hooks($module, $element) {
$theme_hooks = array();
if ($module == 'node') {
$theme_hooks = array(
'node__' . $element,
'node',
);
}
return $theme_hooks;
}
/**
* Implements hook_skinr_elements().
*/
function node_skinr_elements($variables, $hook) {
$elements = array();
if ($hook == 'node') {
$elements['node'] = array($variables['node']->type);
}
return $elements;
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* @file
* Implements Skinr hooks for views.module.
*/
/**
* Implements hook_skinr_config_info().
*/
function views_skinr_config_info() {
return array('views');
}
/**
* Implements hook_skinr_theme_hooks().
*/
function views_skinr_theme_hooks($module, $element) {
$theme_hooks = array();
if ($module == 'views') {
list($name, $display_id) = explode('__', $element, 2);
if ($view = views_get_view($name)) {
$view->execute_display($display_id);
$display = $view->display[$view->current_display];
// Create list of suggested templates.
$theme_hooks = views_theme_functions('views_view', $view, $display);
// @todo Determine whether below code is still relevant.
/*
// Fetch additional style based suggested templates.
$additional_hooks = views_theme_functions($display->display_plugin, $view, $display);
$theme_hooks = array_merge($additional_hooks, $theme_hooks);
*/
}
else {
$theme_hooks[] = 'views_view';
}
}
return $theme_hooks;
}
/**
* Implements hook_skinr_elements().
*/
function views_skinr_elements($variables, $hook, $op) {
$elements = array();
if ($op == 'preprocess' && $hook == 'views_view') {
$elements['views'] = array($variables['view']->name . '__' . $variables['view']->current_display);
}
elseif ($op == 'contextual_links' && $hook == 'page' && isset($variables['page']['#views_contextual_links_info'])) {
// Contextual links for views are on 'page' hook, not 'views_view'.
$elements['views'] = array($variables['page']['#views_contextual_links_info']['views_ui']['view_name'] . '__' . $variables['page']['#views_contextual_links_info']['views_ui']['view_display_id']);
}
return $elements;
}

View File

@@ -0,0 +1,416 @@
<?php
/**
* @file
* This file contains no working PHP code; it exists to provide additional documentation
* for doxygen as well as to document hooks in the standard Drupal manner.
*/
/**
* @mainpage Skinr API Manual
*
* Topics:
* - @ref skinr_hooks
*/
/**
* @defgroup skinr_hooks Skinrs hooks
* @{
* Hooks that can be implemented by other modules in order to implement the
* Skinr API.
*/
/**
* Configure Skinr for this module.
*
* This hook should be placed in MODULENAME.skinr.inc and it will be auto-loaded.
* This must either be in the same directory as the .module file or in a subdirectory
* named 'includes'.
*
* @return
* An array of element types this module supports.
*/
function hook_skinr_config() {
return array('block');
}
/**
* Provide a list of all available theme hooks for a given element.
*
* @param $module
* The module implementing given element.
* @param $element
* An element.
*
* @return
* An array of theme hooks.
*/
function hook_skinr_theme_hooks($module, $element) {
$theme_hooks = array();
if ($module == 'node') {
$theme_hooks = array(
'node_' . $element,
'node',
);
}
return $theme_hooks;
}
/**
* Perform alterations to theme hooks before widgets are rendered.
*
* @param $theme_hooks
* An array of theme hooks.
* @param $module
* The module implementing given element.
* @param $element
* An element.
*/
function hook_skinr_theme_hooks_alter(&$theme_hooks, $module, $element) {
if ($module == 'node') {
array_unshift($theme_hooks, 'node_' . $element . '_custom');
}
}
/**
* Return an array of element ids.
*
* @todo Needs a better description.
*
* @param $variables
* The variables array from skinr_preprocess().
* @param $hook
* The name of the theme hook.
* @param $op
* The operation being performed:
* - 'preprocess'
* - 'contextual_links'
*
* @return
* An array of element arrays, keyed by element type. Example:
* @code
* array(
* 'block' => array('system__navigation'),
* );
* @endcode
*
* @see skinr_preprocess()
*/
function hook_skinr_elements(&$variables, $hook, $op) {
$elements = array();
if ($hook == 'block') {
$elements['block'] = array($variables['block']->module . '__' . $variables['block']->delta);
}
return $elements;
}
/**
* Define the API version of Skinr your code is compatible with.
*
* This is required when creating a new Skinr plugin. It checks to make sure
* your Skins are compatible with the installed version of Skinr and takes care
* of loading the include files.
*
* @return
* An associative array describing Skinr API integration:
* - directory: (optional) The name of a sub-directory, in which include files
* containing skin or group definitions may be found.
* - path: (optional) The path to the directory containing the directory
* specified in 'directory'. Defaults to the path of the module or theme
* implementing the hook.
* In case no Skinr plugin include files exist for your implementation, simply
* define the function with an empty function body.
*
* The "hook" prefix is substituted with the name of the module or theme that
* implements it, e.g. THEME_skinr_api_VERSION() in template.php, or
* MODULE_skinr_api_VERSION() in MODULE.module.
*
* VERSION is normally identical to Skinr's major version; e.g., "2".
*/
function hook_skinr_api_VERSION() {
return array(
'path' => drupal_get_path('module', 'mymodule'),
'directory' => 'skins',
);
}
/**
* Define the skin(s) for this Skinr plugin.
*
* Each skin definition consists of properties that define its form element and
* settings that are needed to make it work, such as the class(es) Skinr should
* apply, which files it should load, whether or not it should be disabled by
* default and which theme hook(s) it was designed to work with.
*
* Each skin name must be unique. Skins cannot have the same name even if they
* are located in different plugins. It is recommended to prefix the name of
* each skin with the name of the theme or module implementing it.
*
* Skin settings:
* - title (required): Title of the skin form element.
* - description (optional): Description of the skin form element.
* - group (optional): The group the skin is attached to; defaults to a Skinr
* provided group labeled "General."
* - type (optional): The type of form element. Allowed values:
* - checkboxes (default): Useful when single or multiple options can be
* chosen. This type does not need to be set manually. Skinr will apply
* it by default.
* - select: Useful when a single option can be chosen, but many exist.
* - radios: Useful when a single option can be chosen and only a few options
* exist.
* - weight (discouraged): Sets the weight of the skin inside the group; NULL
* by default. weight should not be set on each individual skin. Instead, it
* should be used sparingly where positioning a skin at the very top or
* bottom is desired.
* - attached (optional): A array containing information about CSS and
* JavaScript files the skin requires. Each entry is an array keyed by type:
* - css (optional): Maps to the functionality of drupal_add_css() with one
* exception: paths are automatically assumed relative to the plugin
* directory, unless external. Examples:
* - Simple:
* 'css' => array('css/skin-name.css')
* - Advanced:
* 'css' => array(
* array('css/skin-name-ie.css', array(
* 'media' => 'screen',
* 'browsers' => array('IE' => 'lte IE 8'),
* ),
* )
* - js (optional): Maps to the functionality of drupal_add_js() with one
* exception: paths are automatically assumed as relative to the plugin
* directory, unless external. Examples:
* - Simple:
* 'js' => array('js/skin-name.js')
* - Advanced:
* 'js' => array(
* array(
* 'js/skin-name-advanced.js',
* array(
* 'scope' => 'footer',
* 'group' => JS_THEME,
* ),
* )
* - options (required): An array containing one or more options (also arrays)
* for the user to choose from when applying skins. Each option key should be
* a machine name describing the option. An option should including the
* following keys:
* - title (required): The option label.
* - class (required): An array containing one or more classes the skin
* should apply. All classes should be entered as an array: For example:
* 'class' => array('class-b', 'class-b')
* - attached (optional): Same syntax as above, but applies to a specific
* option only.
* - theme hooks (optional): An array containing certain allowed theme hooks,
* which allow you to limit where the skin can be used. Allowed options
* include: block, block__MODULE, comment_wrapper,comment__wrapper_NODETYPE,
* node, node__NODETYPE, region, region__REGIONNAME, panels_display,
* panels_region, panels_pane, views_view, views_view__STYLENAME,
* views_view__DISPLAYNAME, and views_view__VIEWNAME.
* - default status (optional): Skins are disabled by default to keep UI
* clutter to a minimum. In some cases, like contrib themes, it makes sense to
* enable skins which are required to make the theme work properly by default.
* Setting this property to 1 will cause it to be enabled by default for all
* installed themes.
* - status: (optional) An associative array whose keys are theme names and
* whose corresponding values denote the desired default status for the
* particular theme.
*
* The "hook" prefix is substituted with the name of the module or theme
* implementing it.
*/
function hook_skinr_skin_info() {
$skins['skinr_menus'] = array(
'title' => t('Menu styles'),
'description' => t('Select a style to use for the main navigation.'),
'type' => 'select',
'group' => 'skinr_menus',
'theme hooks' => array('block__menu', 'block__menu_block'),
'attached' => array(
'css' => array('css/nav.css'),
),
'options' => array(
'one_level' => array(
'title' => t('Standard (1 level) - No colors'),
'class' => array('nav'),
),
'menu_a' => array(
'title' => t('Standard (1 level) - Green'),
'class' => array('nav', 'nav-a'),
'attached' => array('css' => array('css/nav-colors.css')),
),
'menu_b' => array(
'title' => t('Standard (1 level) - Blue'),
'class' => array('nav', 'nav-b'),
'attached' => array('css' => array('css/nav-colors.css')),
),
'menu_c' => array(
'title' => t('Dropdowns - No colors'),
'class' => array('nav', 'nav-dd'),
'attached' => array(
'css' => array('css/nav-dd.css'),
'js' => array('js/dropdown.js'),
),
),
'menu_d' => array(
'title' => t('Dropdowns - Green'),
'class' => array('nav', 'nav-dd', 'nav-a'),
'attached' => array(
'css' => array('css/nav-dd.css'),
'js' => array('js/dropdown.js'),
),
),
'menu_e' => array(
'title' => t('Dropdowns - Blue'),
'class' => array('nav', 'nav-dd', 'nav-b'),
'attached' => array(
'css' => array('css/nav-dd.css'),
'js' => array('js/dropdown.js'),
),
),
),
// Optional: Specify a global default status for this skin, making it
// available or unavailable to all themes.
'default status' => 0,
// Optional: Specify a default status for a particular theme. This mainly
// makes sense for skins provided by themes only.
'status' => array(
'bartik' => 1,
'garland' => 0,
// In case you are registering a skin for your base theme, then you likely
// do not know which sub themes are going to use your base theme. By
// setting the global default status to 0 (as above) and enabling the skin
// for your base theme itself, the skin's status will be automatically
// inherited to all sub themes of your base theme.
'mybasetheme' => 1,
),
);
return $skins;
}
/**
* Define one or more skins in an atomic Skinr plugin file.
*
* This hook works identically to hook_skinr_skin_info(), but allows to place
* one or more related skin definitions into a separate plugin file.
*
* For example, considering a module or theme with the name "extension" that
* contains an include file:
* @code
* extension/skins/example/example.inc
* @encode
* The "hook" prefix is substituted with the name of the module or theme
* implementing it ("extension"), and PLUGIN is substituted with the name of the
* include file ("example"), e.g., THEME_skinr_skin_PLUGIN_info() or
* MODULE_skinr_skin_PLUGIN_info(). For above example, the function name would
* be: extension_skinr_skin_example_info().
*/
function hook_skinr_skin_PLUGIN_info() {
$skins['extension_example_menus'] = array(
'title' => t('Example menu styles'),
'type' => 'select',
'group' => 'skinr_menus',
'theme hooks' => array('block__menu', 'block__menu_block'),
'attached' => array(
'css' => array('css/nav.css'),
),
'options' => array(
'menu_a' => array(
'title' => t('Standard (1 level) - Green'),
'class' => array('nav', 'nav-a'),
'attached' => array('css' => array('css/nav-colors.css')),
),
'menu_b' => array(
'title' => t('Standard (1 level) - Blue'),
'class' => array('nav', 'nav-b'),
'attached' => array('css' => array('css/nav-colors.css')),
),
),
);
return $skins;
}
/**
* Perform alterations on Skinr skins.
*
* @param $skins
* An array of skin information exposed by hook_skinr_skin_info()
* implementations.
*/
function hook_skinr_skin_info_alter(&$skins) {
// Remove restrictions on theme hooks the skin works with.
unset($skins['skinr_menus']['theme hooks']);
}
/**
* Defines group(s) that will contain skins.
*
* Groups are form element containers used to organize skins categorically. If
* you do not define a group, your skins will appear in Skinr's default group,
* which is labeled "General." Skinr implements 4 default groups, which may be
* used in any skin implementation. For more information, see skins/default.inc.
*
* Each group name must be unique. It is recommended to prefix the name of each
* group with the name of the theme or module name implementing it, followed by
* the name of the group. Note that you cannot define 2 groups with the same
* name, even if they are in different plugins.
*
* Group properties:
* - title (required): Brief title of the tab.
* - description (optional): Description of the group for administration page.
* - weight (discouraged): Weight of the tab group; 0 by default.
*
* The "hook" prefix is substituted with the name of the module or theme that
* implements it.
*
* @see skinr_default_skinr_group_info()
*/
function hook_skinr_group_info() {
$group['skinr_menus'] = array(
'title' => t('Menus'),
'description' => t('Menu and navigation styles.'),
);
return $groups;
}
/**
* Define one or more skin groups in an atomic Skinr plugin file.
*
* This hook works identically to hook_skinr_group_info(), but allows to place
* one or more related skin group definitions into a separate plugin file.
*
* For example, considering a module or theme with the name "extension" that
* contains an include file:
* @code
* extension/skins/example/example.inc
* @encode
* The "hook" prefix is substituted with the name of the module or theme
* implementing it ("extension"), and PLUGIN is substituted with the name of the
* include file ("example"), e.g., THEME_skinr_group_PLUGIN_info() or
* MODULE_skinr_group_PLUGIN_info(). For above example, the function name would
* be: extension_skinr_group_example_info().
*/
function hook_skinr_group_PLUGIN_info() {
$group['extension_example_menus'] = array(
'title' => t('Menus'),
'description' => t('Menu and navigation styles.'),
);
return $groups;
}
/**
* Perform alterations on Skinr groups.
*
* @param $groups
* An array of group information exposed by hook_skinr_group_info()
* implementations.
*/
function hook_skinr_group_info_alter(&$groups) {
// Show this tab group at the top of the Skinr settings form.
$groups['skinr_menus']['weight'] = -1;
}
/**
* @}
*/

View File

@@ -0,0 +1,13 @@
name = Skinr
description = Provides a way to define and/or skin bits of Drupal output from the UI.
package = Skinr
core = 7.x
files[] = tests/skinr.test
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,199 @@
<?php
/**
* @file
* Contains install, update, and uninstall functions for Skinr.
*/
/**
* Implements hook_schema().
*/
function skinr_schema() {
$schema['skinr_skins'] = array(
'description' => 'Stores skinr data.',
'fields' => array(
'sid' => array(
'description' => 'The primary identifier for a skin configuration.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'theme' => array(
'description' => 'The theme this configuration applies to.',
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
),
'module' => array(
'description' => 'The module this configuration applies to.',
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
),
'element' => array(
'description' => 'The element this configutation applies to.',
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => '',
),
'skin' => array(
'description' => 'The skin that has been applied.',
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
),
'options' => array(
'description' => 'A serialized array containing the skin options that have been applied.',
'type' => 'text',
'size' => 'big',
'not null' => TRUE,
'serialize' => TRUE,
),
'status' => array(
'description' => 'Boolean indicating whether or not this item is enabled.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
),
),
'primary key' => array('sid'),
'unique keys' => array(
'theme_module_element_skin' => array('theme', 'module', 'element', 'skin'),
),
'indexes' => array(
'theme' => array('theme'),
'module' => array('theme', 'module'),
'element' => array('theme', 'module', 'element'),
'skin' => array('skin'),
),
);
$schema['skinr_rules'] = array(
'description' => 'Stores skinr rule data.',
'fields' => array(
'rid' => array(
'type' => 'serial',
'not null' => TRUE,
'description' => 'Primary Key: Unique skinr rule ID.',
),
'title' => array(
'description' => 'The administrative title for this rule.',
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => '',
),
'rule_type' => array(
'description' => 'The content type of this rule.',
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => '',
),
'node_types' => array(
'type' => 'text',
'size' => 'normal',
'not null' => FALSE,
'serialize' => TRUE,
'description' => 'A serialized array of node types for this record.',
),
'roles' => array(
'type' => 'text',
'size' => 'normal',
'not null' => FALSE,
'serialize' => TRUE,
'description' => 'A serialized array of roles for this record.',
),
'visibility' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
'description' => 'Flag to indicate how to show rules on pages. (0 = Show on all pages except listed pages, 1 = Show only on listed pages, 2 = Use custom PHP code to determine visibility)',
),
'pages' => array(
'type' => 'text',
'not null' => TRUE,
'description' => 'Contains either a list of paths on which to include/exclude the rule or PHP code, depending on "visibility" setting.',
),
),
'primary key' => array('rid'),
);
return $schema;
}
/**
* Implements hook_uninstall().
*/
function skinr_uninstall() {
// Remove all skinr variables.
db_delete('variable')
->condition('name', 'skinr_%', 'LIKE')
->execute();
}
/**
* Implements hook_update_last_removed().
*
* Make sure any previous updates aren't skipped.
*/
function skinr_update_last_removed() {
// @todo We probably shouldn't expect people to have ever installed
// Skinr version 6.x-2.x, where updates 6000 through 6003 are from.
return 6004;
}
/**
* Install new skinr tables and convert old variables to the new db system.
*
* @todo Shoud we remove this? It was ported from skinr_update_6000(), but
* shouldn't have been.
*
* Contents removed because the table added here is no longer required.
*/
function skinr_update_7001() {
}
/**
* Install a new field in {skinr_rules} table.
*
* @todo Should we remove this? It was ported from skinr_update_6001(), but
* shouldn't have been.
*/
function skinr_update_7002() {
// @todo skinr_update_6001() contains additional field manipulations.
if (!db_field_exists('skinr_rules', 'rule_type')) {
db_add_field('skinr_rules', 'rule_type', array(
'description' => 'The content type of this rule.',
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => '',
));
db_update('skinr_rules')
->fields(array('rule_type' => 'page'))
->execute();
db_update('skinr')
->fields(array('module' => 'rules'))
->condition('module', 'page')
->execute();
}
}
/**
* Install the new {skinr_skinsets} and {skinr_skins} tables.
*
* @todo Should we remove this? It was ported from skinr_update_6002() and
* skinr_update_6003(), but should not have been.
*
* Contents removed because the tables added here are no longer required.
*/
function skinr_update_7003() {
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
<?php
/**
* @file
* Implements page and region level rules, and adds default groups.
*/
/**
* Implements hook_skinr_api_VERSION().
*/
function skinr_skinr_api_2() {
}
/**
* Implements hook_skinr_group_info().
*/
function skinr_skinr_group_info() {
$groups['general'] = array(
'title' => t('General'),
'description' => t('Styles for content such as lists, buttons, margins, padding, etc.'),
'weight' => -10,
);
$groups['box'] = array(
'title' => t('Box styles'),
'description' => t('Presentational styles for the container.'),
);
$groups['typography'] = array(
'title' => t('Typography'),
'description' => t('Fonts, styles, sizes and other typography related skins.'),
);
$groups['layout'] = array(
'title' => t('Layout'),
'description' => t('Grid, layout and other structural related skins.'),
);
return $groups;
}
/**
* Implementation of hook_skinr_config_info().
*/
function skinr_skinr_config_info() {
return array('rules');
}
/**
* Implements hook_skinr_theme_hooks().
*/
function skinr_skinr_theme_hooks($module, $element) {
$theme_hooks = array();
if ($module == 'rules') {
$rule = skinr_rule_load($element);
$hooks = explode('__', $rule->rule_type);
while (count($hooks)) {
$theme_hooks[] = implode('__', $hooks);
array_pop($hooks);
}
}
return $theme_hooks;
}
/**
* Implements hook_skinr_elements().
*/
function skinr_skinr_elements($variables, $hook) {
$elements = array();
if ($hook == 'html' || $hook == 'region') {
$elements['rules'] = array();
$rule_type = 'page';
if ($hook == 'region') {
$rule_type = 'region__' . $variables['region'];
}
$rules = skinr_rule_load_multiple(array(), array('rule_type' => $rule_type));
foreach ($rules as $rule) {
if (skinr_rule_is_visible($rule->rid)) {
$elements['rules'][] = $rule->rid;
}
}
}
return $elements;
}

View File

@@ -0,0 +1,14 @@
name = Skinr Panels
description = Provides Skinr integration with Panels.
package = Skinr
core = 7.x
dependencies[] = panels
files[] = tests/skinr_panels.test
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,115 @@
<?php
/**
* @file
* Provides Skinr integration with Panels.
*
* NOTE: When panels are stored in code, rather than DB, we run into lack of
* context problems. See the below link for a workaround. This is a limitation
* with the Panels module.
*
* @link http://drupal.org/node/1160924 Undefined property: stdClass::$did in panels_skinr_preprocess_index_handler() @endlink
* @link http://drupal.org/node/1292662 Workaround for undefined property: stdClass::$did in panels_skinr_preprocess_index_handler() @endlink
*/
/**
* Implements hook_skinr_api().
*/
function skinr_panels_skinr_api_2() {
return array();
}
/**
* Implements hook_theme_registry_alter().
*
* Re-order preprocess functions to prioritize skinr_ui_preprocess, which adds
* contextual links, over template_preprocess_HOOK functions. This fixes a
* problem with the way panels handles contextual links.
*/
function skinr_panels_theme_registry_alter(&$theme_registry) {
$preprocess_functions = array();
foreach ($theme_registry['panels_pane']['preprocess functions'] as $function) {
if ($function == 'skinr_ui_preprocess' || $function == 'skinr_panels_preprocess') {
continue;
}
$preprocess_functions[] = $function;
if ($function == 'template_preprocess') {
// Insert our preprocess function right after template_preprocess to give it priority over template_preprocess_HOOK functions.
$preprocess_functions[] = 'skinr_panels_preprocess';
$preprocess_functions[] = 'skinr_ui_preprocess';
}
}
$theme_registry['panels_pane']['preprocess functions'] = $preprocess_functions;
// Add a preprocess function to theme_links(). This is a total hack.
$theme_registry['links']['preprocess functions'][] = 'skinr_panels_preprocess_links';
}
/**
* Implements hook_preprocess().
*/
function skinr_panels_preprocess(&$variables, $hook) {
if ($hook == 'panels_pane' && user_access('edit skin settings')) {
// Get contextual links.
$contextual_links = array();
$counter = 0;
$array_elements = skinr_invoke_all('skinr_elements', $variables, $hook, 'contextual_links');
$module = 'panels';
$elements = $array_elements[$module];
foreach ($elements as $element) {
$contextual_links['skinr-' . $module . '-' . $counter++] = array(
'admin/structure/skinr/edit/nojs', array($module, $element),
);
}
if (!empty($contextual_links)) {
// Need to set contextual links through Skinr API so we have a valid, and
// consistent, link title. It's also used in our hook_preprocess_links()
// hack.
_skinr_ui_set_contextual_links($hook, $contextual_links);
// Render links.
$element = array(
'#type' => 'contextual_links',
'#contextual_links' => $contextual_links,
);
$element = contextual_pre_render_links($element);
// Add in the Skinr links.
if (isset($variables['content']->admin_links) && is_array($variables['content']->admin_links)) {
$variables['content']->admin_links += $element['#links'];
}
else {
$variables['content']->admin_links = $element['#links'];
}
}
}
}
/**
* Implements hook_preprocess_links().
*
* This hack is panels on panel pages only.
*/
function skinr_panels_preprocess_links(&$variables, $hook) {
if (isset($variables['links'][0]['title']) && $variables['links'][0]['title'] == t('Edit @type', array('@type' => 'Panel')) && user_access('edit skin settings')) {
// Get contextual links.
$contextual_links = skinr_ui_get_contextual_links();
if (isset($contextual_links['panels_pane'])) {
$contextual_links = $contextual_links['panels_pane'];
// Render links.
$element = array(
'#type' => 'contextual_links',
'#contextual_links' => $contextual_links,
);
$element = contextual_pre_render_links($element);
// Hack in the Skinr links.
$variables['links'] += $element['#links'];
}
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* @file
* Implements Skinr hooks for panels.module.
*/
/**
* Implements hook_skinr_config_info().
*/
function skinr_panels_skinr_config_info() {
return array('panels');
}
/**
* Implements hook_skinr_theme_hooks().
*/
function skinr_panels_skinr_theme_hooks($module, $element) {
$theme_hooks = array();
if ($module == 'panels') {
if (strpos($element, 'region') === 0) {
$theme_hooks[] = 'panels_region';
}
elseif (strpos($element, 'pane') === 0) {
$theme_hooks[] = 'panels_pane';
}
else {
$theme_hooks[] = 'panels_display';
}
}
return $theme_hooks;
}
/**
* Implements hook_skinr_elements().
*/
function skinr_panels_skinr_elements($variables, $hook) {
$elements = array();
if ($hook == 'panels_pane') {
$elements['panels'] = array('pane__' . $variables['pane']->did . '__' . $variables['pane']->pid);
}
return $elements;
}

View File

@@ -0,0 +1,153 @@
<?php
/**
* @file
* Tests for the Skinr Panels module.
*/
/**
* Tests UI functionality for Panels plugin.
*/
class SkinrPanelsTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Plugins UI - Panels',
'description' => 'Tests Skinr UI functionality for functionality plugin from Panels.',
'dependencies' => array('ctools', 'page_manager', 'panels', 'panels_node', 'panels_mini'),
'group' => 'Skinr',
);
}
function setUp() {
parent::setUp(array('block', 'page_manager', 'panels_node', 'panels_mini', 'skinr_panels_test'));
$this->admin_user = $this->drupalCreateUser(array(
'administer blocks',
'use page manager',
'administer page manager',
'create mini panels',
'administer mini panels',
'access contextual links',
'administer skinr',
'edit skin settings',
'edit advanced skin settings',
'bypass node access',
));
$this->drupalLogin($this->admin_user);
}
/**
* Tests panels plugin.
*
* @todo The below test doesn't work due to CTools/Panels not passing along
* enough data to create unique element ids when panels are in code. Skinr
* currently doesn't support panels in code.
*/
function xtestPanelsDefault() {
// Test panels pages.
// Go to panel page.
$this->drupalGet('skinr-panels-test-panel');
// Make sure our contextual link appears on the page.
$this->assertLinkByHref('admin/structure/skinr/edit/nojs/panels/pane__1__1/configure', 0, "Contexual link to edit pane's skin configuration on panel page (stored in code) was found.");
$this->drupalGet('admin/structure/mini-panels');
// Test mini panels.
// Add the mini block to the sidebar.
$default_theme = variable_get('theme_default', 'bartik');
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'panels_mini',
'delta' => 'skinr_panels_test_mini_panel',
))
->fields(array(
'status' => 1,
'region' => 'sidebar_first',
'pages' => '',
))
->execute();
// Go front page.
$this->drupalGet('');
// Make sure our contextual link appears on the page.
// @todo Is there a better way to determine did and pid used for this panel?
$this->assertLinkByHref('admin/structure/skinr/edit/nojs/panels/pane__2__2/configure', 0, 'Contexual link to edit pane\'s skin configuration on mini panel (stored in code) was found.');
}
/**
* Tests panels plugin.
*/
function testPanelsDatabase() {
// Create a simple panel node.
$node = $this->drupalCreateNode(array(
'type' => 'panel',
'panels_node' => array(
'layout' => 'onecol',
'css_id' => '',
'pipeline' => 'standard',
),
));
// Add a block to our panel node.
$display = panels_load_display($node->panels_node['did']);
$pane = panels_new_pane('block', 'system-user-menu', TRUE);
$display->add_pane($pane, 'middle');
$this->assertTrue(panels_save_display($display), 'Block was successfully added to panel node.');
// Go to node.
$uri = entity_uri('node', $node);
$this->drupalGet($uri['path']);
// Make sure our contextual link appears on the page.
// @todo Is there a better way to determine did and pid used for this panel?
$this->assertLinkByHref('admin/structure/skinr/edit/nojs/panels/pane__1__1/configure', 0, 'Contexual link to edit pane\'s skin configuration on panel node was found.');
// Test panels pages.
// Save page to DB.
$task = page_manager_get_task('page');
$handler = page_manager_load_task_handler($task, 'skinr_panels_test', 'page_skinr_panels_test_panel_context');
page_manager_save_task_handler($handler);
// Go to panel page.
$this->drupalGet('skinr-panels-test-panel');
// Make sure our contextual link appears on the page.
$this->assertLinkByHref('admin/structure/skinr/edit/nojs/panels/pane__2__2/configure', 0, "Contexual link to edit pane's skin configuration on panel page (stored in DB) was found.");
// Test mini panels.
// Save mini panel to DB.
$mini = panels_mini_load('skinr_panels_test_mini_panel');
panels_mini_save($mini);
// Add the mini block to the sidebar.
$default_theme = variable_get('theme_default', 'bartik');
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'panels_mini',
'delta' => 'skinr_panels_test_mini_panel',
))
->fields(array(
'status' => 1,
'region' => 'sidebar_first',
'pages' => '',
))
->execute();
// Go front page.
$this->drupalGet('');
// Make sure our contextual link appears on the page.
// @todo Is there a better way to determine did and pid used for this panel?
$this->assertLinkByHref('admin/structure/skinr/edit/nojs/panels/pane__3__3/configure', 0, 'Contexual link to edit pane\'s skin configuration on mini panel (stored in DB) was found.');
}
}

View File

@@ -0,0 +1,71 @@
<?php
$page = new stdClass;
$page->disabled = FALSE; /* Edit this to true to make a default page disabled initially */
$page->api_version = 1;
$page->name = 'skinr_panels_test';
$page->task = 'page';
$page->admin_title = 'Skinr Panels Test';
$page->admin_description = 'Skinr Panels Test panels page.';
$page->path = 'skinr-panels-test-panel';
$page->access = array();
$page->menu = array();
$page->arguments = array();
$page->conf = array(
'admin_paths' => FALSE,
);
$page->default_handlers = array();
$handler = new stdClass;
$handler->disabled = FALSE; /* Edit this to true to make a default handler disabled initially */
$handler->api_version = 1;
$handler->name = 'page_skinr_panels_test_panel_context';
$handler->task = 'page';
$handler->subtask = 'skinr_panels_test';
$handler->handler = 'panel_context';
$handler->weight = 0;
$handler->conf = array(
'title' => 'Panel',
'no_blocks' => 0,
'pipeline' => 'standard',
'css_id' => '',
'css' => '',
'contexts' => array(),
'relationships' => array(),
);
$display = new panels_display;
$display->layout = 'onecol';
$display->layout_settings = array();
$display->panel_settings = array(
'style_settings' => array(
'default' => NULL,
'middle' => NULL,
),
);
$display->cache = array();
$display->title = '';
$display->content = array();
$display->panels = array();
$pane = new stdClass;
$pane->pid = 'new-1';
$pane->panel = 'middle';
$pane->type = 'block';
$pane->subtype = 'system-user-menu';
$pane->shown = TRUE;
$pane->access = array();
$pane->configuration = array(
'override_title' => 0,
'override_title_text' => '',
);
$pane->cache = array();
$pane->style = array(
'settings' => NULL,
);
$pane->css = array();
$pane->extras = array();
$pane->position = 0;
$display->content['new-1'] = $pane;
$display->panels['middle'][0] = 'new-1';
$display->hide_title = PANELS_TITLE_FIXED;
$display->title_pane = 'new-1';
$handler->conf['display'] = $display;
$page->default_handlers[$handler->name] = $handler;

View File

@@ -0,0 +1,48 @@
<?php
$mini = new stdClass;
$mini->disabled = FALSE;
$mini->api_version = 1;
$mini->name = 'skinr_panels_test_mini_panel';
$mini->category = '';
$mini->admin_title = 'Skinr Panels Test mini panel';
$mini->admin_description = 'Skinr Panels Test mini panel.';
$mini->requiredcontexts = array();
$mini->contexts = array();
$mini->relationships = array();
$display = new panels_display;
$display->layout = 'onecol';
$display->layout_settings = array();
$display->panel_settings = array(
'style_settings' => array(
'default' => NULL,
'middle' => NULL,
),
);
$display->cache = array();
$display->title = '';
$display->content = array();
$display->panels = array();
$pane = new stdClass;
$pane->pid = 'new-1';
$pane->panel = 'middle';
$pane->type = 'block';
$pane->subtype = 'system-user-menu';
$pane->shown = TRUE;
$pane->access = array();
$pane->configuration = array(
'override_title' => 0,
'override_title_text' => '',
);
$pane->cache = array();
$pane->style = array(
'settings' => NULL,
);
$pane->css = array();
$pane->extras = array();
$pane->position = 0;
$display->content['new-1'] = $pane;
$display->panels['middle'][0] = 'new-1';
$display->hide_title = PANELS_TITLE_FIXED;
$display->title_pane = '0';
$mini->display = $display;

View File

@@ -0,0 +1,14 @@
name = Skinr Panels Testing
description = A test module used for testing Skinr Panels.
package = Testing
core = 7.x
hidden = TRUE
dependencies[] = skinr_panels
dependencies[] = skinr_ui
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,15 @@
<?php
/**
* @file
* Skinr Panels testing module.
*/
/**
* Implementation of hook_ctools_plugin_api().
*/
function skinr_panels_test_ctools_plugin_api($module, $api) {
if (($module == 'page_manager' && $api == 'pages_default') || ($module == 'panels_mini' && $api == 'panels_default')) {
return array('version' => 1);
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* @file
* Default pages.
*/
/**
* Implementation of hook_default_page_manager_pages().
*/
function skinr_panels_test_default_page_manager_pages() {
static $pages;
if (isset($pages)) {
return $pages;
}
$files = file_scan_directory(drupal_get_path('module', 'skinr_panels_test') . '/pages_default', '/\.inc$/');
foreach ($files as $filepath => $file) {
include $filepath;
if (isset($page)) {
$pages[$page->name] = $page;
}
}
return $pages;
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* @file
* skinr_panels_test.panels_default.inc
*/
/**
* Implementation of hook_default_panels_mini().
*/
function skinr_panels_test_default_panels_mini() {
static $minis;
if (isset($minis)) {
return $minis;
}
$files = file_scan_directory(drupal_get_path('module', 'skinr_panels_test') . '/panels_default', '/\.inc$/');
foreach ($files as $filepath => $file) {
include $filepath;
if (isset($mini)) {
$minis[$mini->name] = $mini;
}
}
return $minis;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
<?php
/**
* @file
* This file contains no working PHP code; it exists to provide additional documentation
* for doxygen as well as to document hooks in the standard Drupal manner.
*/
/**
* @mainpage Skinr UI API Manual
*
* Topics:
* - @ref skinr_ui_hooks
*/
/**
* @defgroup skinr_ui_hooks Skinr UIs hooks
* @{
* Hooks that can be implemented by other modules in order to implement the
* Skinr UI API.
*/
/**
* @}
*/

View File

@@ -0,0 +1,14 @@
name = Skinr UI
description = Administrative interface to skinr. Without this module, you cannot edit your skins.
package = Skinr
core = 7.x
configure = admin/structure/skinr
dependencies[] = skinr
files[] = tests/skinr_ui.test
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,39 @@
<?php
/**
* @file
* Contains install, update, and uninstall functions for Skinr UI.
*/
/**
* Implements hook_install().
*/
function skinr_ui_install() {
// Skinr should go before contextual module.
db_update('system')
->fields(array('weight' => -1))
->condition('name', 'skinr_ui')
->execute();
}
/**
* Implements hook_uninstall().
*/
function skinr_ui_uninstall() {
variable_del('skinr_overlay_width');
variable_del('skinr_overlay_height');
}
/**
* Delete a few unused variables.
*
* @todo This is a badly converted function it should be
* skinr_ui_update_6001(). Remove this function and implement
* skinr_update_last_removed() instead.
*/
function skinr_ui_update_7000() {
variable_del('skinr_overlay_autofit');
variable_del('skinr_overlay_draggable');
return array(array('success' => TRUE, 'query' => "Some variables that are no longer used have been deleted."));
}

View File

@@ -0,0 +1,853 @@
<?php
/**
* @file
* Handles Skinr UI functionality allowing users to apply skins to their site.
*/
/**
* Implements hook_permission().
*/
function skinr_ui_permission() {
return array(
'administer skinr' => array(
'title' => t('Administer Skinr'),
),
'edit skin settings' => array(
'title' => t('Edit skin settings.'),
),
'edit advanced skin settings' => array(
'title' => t('Edit advanced skin settings'),
'description' => t('Edit advanced skin settings, such as custom CSS classes.'),
),
);
}
/**
* Determine whether the user has a given privilege.
*
* @param $string
* The permission, such as "administer nodes", being checked for.
* @param $account
* (optional) The account to check, if not given use currently logged in user.
*
* @return
* Boolean TRUE if the current user has the requested permission.
*
* @see user_access()
*/
function skinr_ui_access($string, $account = NULL) {
return user_access($string, $account) || user_access('administer skinr', $account);
}
/**
* Implements hook_menu().
*/
function skinr_ui_menu() {
$items['admin/structure/skinr'] = array(
'title' => 'Skinr',
'description' => 'Manage your skin configurations and rules, import and export skin configurations.',
'page callback' => 'drupal_get_form',
'page arguments' => array('skinr_ui_list'),
'access arguments' => array('administer skinr'),
'file' => 'skinr_ui.admin.inc',
);
$items['admin/structure/skinr/list'] = array(
'title' => 'List',
'description' => t('Manage skinr configurations.'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
// Themes.
$default_theme = variable_get('theme_default', 'bartik');
$items['admin/structure/skinr/library'] = array(
'title' => 'Library',
'description' => 'Manage what skins are available when configuring the way your site looks.',
'page callback' => 'skinr_ui_admin_library',
'page arguments' => array($default_theme),
'access arguments' => array('administer skinr'),
'file' => 'skinr_ui.admin.inc',
'type' => MENU_LOCAL_TASK,
);
foreach (list_themes() as $key => $theme) {
$items['admin/structure/skinr/library/list/' . $key] = array(
'title' => check_plain($theme->info['name']),
'page arguments' => array($key),
'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
'weight' => $key == $default_theme ? -10 : 0,
'access callback' => '_skinr_ui_themes_access',
'access arguments' => array($theme),
'file' => 'skinr_ui.admin.inc',
);
}
// Rules.
$items['admin/structure/skinr/rules'] = array(
'title' => 'Rules',
'page callback' => 'skinr_rules',
'type' => MENU_LOCAL_TASK,
'access arguments' => array('administer skinr'),
'weight' => 1,
'description' => t('Configure region and page level Skinr rules.'),
'file' => 'skinr_ui.rules.inc',
);
$items['admin/structure/skinr/rules/add'] = array(
'title' => 'Create a new rule',
'page callback' => 'drupal_get_form',
'page arguments' => array('skinr_rule_add'),
'type' => MENU_LOCAL_ACTION,
'access arguments' => array('administer skinr'),
'file' => 'skinr_ui.rules.inc',
);
$items['admin/structure/skinr/rules/%skinr_rule/edit'] = array(
'title' => 'Edit rule',
'page callback' => 'drupal_get_form',
'page arguments' => array('skinr_rule_edit', 4),
'type' => MENU_CALLBACK,
'access arguments' => array('administer skinr'),
'file' => 'skinr_ui.rules.inc',
);
$items['admin/structure/skinr/rules/%skinr_rule/delete'] = array(
'title' => 'Delete rule',
'page callback' => 'drupal_get_form',
'page arguments' => array('skinr_rule_delete_confirm', 4),
'type' => MENU_CALLBACK,
'access arguments' => array('administer skinr'),
'file' => 'skinr_ui.rules.inc',
);
// Import & Export.
$items['admin/structure/skinr/import'] = array(
'title' => 'Import',
'page callback' => 'drupal_get_form',
'page arguments' => array('skinr_ui_import_form'),
'type' => MENU_LOCAL_TASK,
'access arguments' => array('administer skinr'),
'weight' => 2,
'description' => t('Import skin configurations.'),
'file' => 'skinr_ui.admin.inc',
);
$items['admin/structure/skinr/export'] = array(
'title' => 'Export',
'page callback' => 'drupal_get_form',
'page arguments' => array('skinr_ui_export_form'),
'type' => MENU_LOCAL_TASK,
'access arguments' => array('administer skinr'),
'weight' => 3,
'description' => t('Export skin configurations.'),
'file' => 'skinr_ui.admin.inc',
);
// Configure skin settings for an element.
$items['admin/structure/skinr/edit/%skinr_js/%/%'] = array(
'title' => 'Edit skin',
'title callback' => 'skinr_ui_edit_title',
'title arguments' => array(5, 6),
'page callback' => 'skinr_ui_edit',
'page arguments' => array(4, 5, 6), // js|nojs, module, element
'type' => MENU_CALLBACK,
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'access arguments' => array('edit skin settings'),
);
$items['admin/structure/skinr/edit/%skinr_js/%/%/configure'] = array(
'title' => 'Edit skin',
'title callback' => 'skinr_ui_edit_contextual_title',
'title arguments' => array(5, 6),
'type' => MENU_DEFAULT_LOCAL_TASK,
'context' => MENU_CONTEXT_INLINE,
);
// Enable a skin configuration.
$items['admin/structure/skinr/skin/%skinr_skin/enable'] = array(
'title' => 'Enable skin',
'page callback' => 'skinr_ui_skin_status_set',
'page arguments' => array(4, TRUE),
'type' => MENU_CALLBACK,
'access arguments' => array('administer skinr'),
'file' => 'skinr_ui.admin.inc',
);
// Disable a skin configuration.
$items['admin/structure/skinr/skin/%skinr_skin/disable'] = array(
'title' => 'Disable skin',
'page callback' => 'skinr_ui_skin_status_set',
'page arguments' => array(4, FALSE),
'type' => MENU_CALLBACK,
'access arguments' => array('administer skinr'),
'file' => 'skinr_ui.admin.inc',
);
// Delete a skin configuration.
$items['admin/structure/skinr/skin/%skinr_skin/delete'] = array(
'title' => 'Delete skin',
'page callback' => 'drupal_get_form',
'page arguments' => array('skinr_ui_delete_confirm', 4),
'type' => MENU_CALLBACK,
'access arguments' => array('administer skinr'),
'file' => 'skinr_ui.admin.inc',
);
return $items;
}
/**
* Helper function to determine if ajax is used to call a function.
*/
function skinr_js_load($js = 'nojs') {
if ($js == 'ajax') {
return TRUE;
}
return 0;
}
/**
* Menu item access callback - only admin or enabled themes can be accessed.
*/
function _skinr_ui_themes_access($theme) {
return user_access('administer skinr') && drupal_theme_access($theme);
}
/**
* Implements hook_theme().
*/
function skinr_ui_theme() {
return array(
'skinr_ui_admin_library_fieldset' => array(
'render element' => 'form',
'file' => 'skinr_ui.admin.inc',
),
'skinr_ui_admin_library_summary' => array(
'variables' => array('name' => NULL, 'description' => NULL),
'file' => 'skinr_ui.admin.inc',
),
);
}
/**
* Implements hook_help().
*/
function skinr_ui_help($path, $arg) {
if (module_exists('advanced_help')) {
$advanced_help = '<p>' . t('Visit the <a href="@skinr-help">help page</a> for full documentation.', array('@skinr-help' => url('admin/advanced_help/skinr'))). '</p>';
}
else {
$advanced_help = '<p>' . t('Please download and enable the <a href="http://drupal.org/project/advanced_help">Advanced Help</a> module for full Skinr documentation.') . '</p>';
}
switch ($path) {
case 'admin/structure/skinr':
return '<p>' . t('Below is a list of all skin configurations in use on this site.') . '</p>' . $advanced_help;
case 'admin/structure/skinr/rule':
return '<p>' . t('Below is a list of Skinr rules. Rules can be created for <em>region</em> and <em>page</em> elements. Start by creating a new rule.') . '</p>';
case 'admin/structure/skinr/rule/add':
return '<p>' . t('Choose the type of rule you wish to create. Page rules apply classes to the &lt;body&gt; tag. Region rules apply to the region wrapper &lt;div&gt; tag.') . '</p>';
case 'admin/structure/skinr/import':
return '<p>' . t('To import skin configurations, paste exported code and click the "Import" button.') . '</p>';
case 'admin/structure/skinr/export':
return '<p>' . t('To export skin configurations, ensure the correct theme is selected and click the "Export" button.') . '</p>';
case 'admin/structure/skinr/edit/%/%/%':
// @todo Make this help text more relevant.
$theme_hooks = skinr_theme_hooks($arg[5], $arg[6]);
return '<p>' . t('Manage which skins you want to apply to the hooks <strong>!hooks</strong>.', array('!hooks' => implode(', ', $theme_hooks))) . '</p>';
case 'admin/structure/skinr/rules/%/edit':
// @todo Make this help text more relevant.
$theme_hooks = skinr_theme_hooks('rules', $arg[4]);
return '<p>' . t('Manage which skins you want to apply to the hooks <strong>!hooks</strong>.', array('!hooks' => implode(', ', $theme_hooks))) . '</p>';
}
}
/**
* Menu title callback; sets the title for a skins configuration form page.
*
* @param $module
* The module that we're editing settings of.
* @param $element
* The element we're editing settings of.
*/
function skinr_ui_edit_title($module, $element) {
return t('Skin settings for !module type !element', array('!module' => $module, '!element' => $element));
}
/**
* Menu title callback; sets the title for a skins configuration form page.
*
* @param $module
* The module that we're editing settings for.
* @param $element
* The element we're editing settings for.
*/
function skinr_ui_edit_contextual_title($module, $element) {
$contextual_links = skinr_ui_get_contextual_links();
foreach ($contextual_links as $hook => $links) {
$counter = 1;
foreach ($links as $link) {
if ($link[1][0] == $module && $link[1][1] == $element) {
if (count($links) > 1) {
return t('Edit skin !number', array('!number' => $counter++));
}
break 2;
}
}
}
return t('Edit skin');
}
/**
* Menu callback; prepares some variables and displays a Skinr edit form.
*
* @param $js
* TRUE if called from javascript, FALSE otherwise.
* @param $module
* The module that we're editing settings of.
* @param $element
* The element of the object we're editing settings of.
* @param $elements
* An array of $element when more than one is returned from the preprocess
* index handler. Used by the javascript UI to update all elements involved.
*/
function skinr_ui_edit($js = FALSE, $module, $element, $elements = NULL) {
if ($js) {
// Do additional ajax related stuff.
}
$arguments = array(
'skinr' => array(
'module' => $module,
'element' => $element,
'elements' => $elements,
),
);
return drupal_get_form('skinr_ui_form', $arguments);
}
/**
* Form builder for the skins configuration form.
*
* @param $arguments
* An array of arguments as passed in by skinr_ui_edit().
*
* @ingroup forms
*/
function skinr_ui_form($form, &$form_state, $arguments) {
$form = array(
'#attributes' => array('class' => 'skinr-form'),
);
$form['skinr']['module'] = array(
'#type' => 'hidden',
'#value' => !empty($form_state['skinr']['module']) ? $form_state['skinr']['module'] : $arguments['skinr']['module'],
);
$form['skinr']['element'] = array(
'#type' => 'hidden',
'#value' => !empty($form_state['skinr']['element']) ? $form_state['skinr']['element'] : $arguments['skinr']['element'],
);
if (!empty($form_state['skinr']['elements']) || !empty($arguments['skinr']['elements'])) {
$form['skinr']['elements'] = array(
'#type' => 'hidden',
'#value' => !empty($form_state['skinr']['elements']) ? $form_state['skinr']['elements'] : $arguments['skinr']['elements'],
);
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
'#weight' => 50,
);
return $form;
}
/**
* Implements hook_form_alter().
*/
function skinr_ui_form_alter(&$form, $form_state, $form_id) {
// Fix for update script.
if ($form_id == 'update_script_selection_form') {
return;
}
// Ensure module and element values are set.
if (empty($form['skinr']['module']['#value']) || empty($form['skinr']['element']['#value'])) {
return;
}
// Check for access.
if (!skinr_ui_access('edit skin settings')) {
// Deny access.
return;
}
$module = $form['skinr']['module']['#value'];
$element = $form['skinr']['element']['#value'];
$groups = skinr_get_group_info();
$skin_infos = skinr_get_skin_info();
// Apply overridden status to skins.
foreach ($skin_infos as $skin_name => $skin_info) {
$skin_infos[$skin_name]['status'] = skinr_skin_info_status_get($skin_infos[$skin_name]);
}
// Invoke hook_skinr_theme_hooks() and hook_skinr_theme_hooks_alter().
$theme_hooks = skinr_theme_hooks($module, $element);
$form['skinr_settings'] = array(
'#tree' => TRUE,
// Set weight to accommodate Rules UI.
'#weight' => 0,
);
$themes = list_themes();
ksort($themes);
// Get current theme, but make sure it's not the admin theme when we're editing with AJAX.
$current_theme = skinr_current_theme(TRUE);
foreach ($themes as $theme) {
if (!$theme->status) {
continue;
}
// If this hook is a region, and the region does not exist for this
// theme, don't bother outputting any of the settings.
if (strpos($theme_hooks[0], 'region') === 0) {
// Strip the region__ part off the region name.
$region = substr($theme_hooks[0], 8);
$regions = system_region_list($theme->name, REGIONS_VISIBLE);
if (!isset($regions[$region])) {
continue;
}
}
if (!$form_state['submitted']) {
$params = array(
'theme' => $theme->name,
'module' => $module,
'element' => $element,
);
if ($skins = skinr_skin_load_multiple(skinr_skin_get_sids($params))) {
$defaults = array();
foreach ($skins as $skin) {
$defaults[$skin->skin] = $skin->options;
}
}
else {
$defaults = array();
}
}
else {
// Handle preview before submit.
// @todo Is this still needed? If so, it needs to be fixed.
$defaults = $form_state['values'];
}
if (!isset($form['skinr_settings'][$module . '_type'])) {
$form['skinr_settings'][$module . '_type'] = array(
'#type' => 'container',
);
if ($module == 'rules') {
$form['skinr_settings']['skinr_settings_title'] = array(
'#type' => 'item',
'#title' => t('Skinr settings'),
'#weight' => -1,
);
}
}
$form['skinr_settings'][$module . '_type'][$theme->name] = array(
'#type' => 'fieldset',
'#title' => $theme->info['name'] . ($theme->name == $current_theme ? ' (' . t('enabled + default') . ')' : ''),
'#collapsible' => TRUE,
'#collapsed' => $theme->name == $current_theme ? FALSE : TRUE,
);
if ($theme->name == $current_theme) {
// Current theme goes at the top.
$form['skinr_settings'][$module . '_type'][$theme->name]['#attributes'] = array('class' => array('skinr-ui-current-theme'));
$form['skinr_settings'][$module . '_type'][$theme->name]['#weight'] = -10;
// Use vertical tabs.
$form['skinr_settings'][$module . '_type'][$theme->name]['groups'] = array(
'#type' => 'vertical_tabs',
);
}
// Create individual widgets for each skin.
foreach ($skin_infos as $skin_name => $skin_info) {
// Check if this skin is disabled.
if (empty($skin_info['status'][$theme->name])) {
continue;
}
// Check if this skin applies to this hook.
if (!is_array($skin_info['theme hooks']) || (!in_array('*', $skin_info['theme hooks']) && !_skinr_is_featured($theme_hooks, $skin_info['theme hooks']))) {
continue;
}
// Create widget.
$field = array();
if (!empty($skin_info['form callback'])) {
// Process custom form callbacks.
// Load include file.
if (!empty($skin_info['source']['filename'])) {
skinr_load_include($skin_info['source']['path'] . '/' . $skin_info['source']['filename']);
}
// Execute form callback.
if (function_exists($skin_info['form callback'])) {
$context = array(
'theme' => $theme->name,
'skin_name' => $skin_name,
'skin_info' => $skin_info,
);
$field = $skin_info['form callback']($form, $form_state, $context);
}
}
else {
switch ($skin_info['type']) {
case 'checkboxes':
$field = array(
'#type' => 'checkboxes',
'#multiple' => TRUE,
'#title' => t($skin_info['title']),
'#options' => skinr_ui_info_options_to_form_options($skin_info['options']),
'#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : array(),
'#description' => t($skin_info['description']),
'#weight' => isset($skin_info['weight']) ? $skin_info['weight'] : NULL,
);
break;
case 'radios':
$field = array(
'#type' => 'radios',
'#title' => t($skin_info['title']),
'#options' => array_merge(array('' => '&lt;none&gt;'), skinr_ui_info_options_to_form_options($skin_info['options'])),
'#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : '',
'#description' => t($skin_info['description']),
'#weight' => isset($skin_info['weight']) ? $skin_info['weight'] : NULL,
);
break;
case 'select':
$field = array(
'#type' => 'select',
'#title' => t($skin_info['title']),
'#options' => array_merge(array('' => '<none>'), skinr_ui_info_options_to_form_options($skin_info['options'])),
'#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : '',
'#description' => t($skin_info['description']),
'#weight' => isset($skin_info['weight']) ? $skin_info['weight'] : NULL,
);
break;
default:
// Raise an error.
drupal_set_message(t("Widget %name's type is invalid.", array('%name' => $skin_name)), 'error', FALSE);
break;
}
}
if (empty($skin_info['group']) || empty($groups[$skin_info['group']])) {
$form['skinr_settings'][$module . '_type'][$theme->name][$skin_name] = $field;
}
else {
if (!empty($field) && !isset($form['skinr_settings'][$module . '_type'][$theme->name]['groups'][$skin_info['group']])) {
$group = $groups[$skin_info['group']];
$form['skinr_settings'][$module . '_type'][$theme->name]['groups'][$skin_info['group']] = array(
'#type' => 'fieldset',
'#title' => t($group['title']),
'#description' => t($group['description']),
'#weight' => isset($group['weight']) ? $group['weight'] : NULL,
);
}
$form['skinr_settings'][$module . '_type'][$theme->name]['groups'][$skin_info['group']][$skin_name] = $field;
}
}
// Check for access.
if (skinr_ui_access('edit advanced skin settings')) {
$skin_name = '_additional';
$form['skinr_settings'][$module . '_type'][$theme->name]['groups']['_additional'] = array(
'#type' => 'fieldset',
'#title' => t('Advanced'),
'#weight' => 50,
);
$form['skinr_settings'][$module . '_type'][$theme->name]['groups']['_additional']['_additional'] = array(
'#type' => 'textfield',
'#title' => t('CSS classes'),
'#size' => 40,
'#description' => t('To add CSS classes manually, enter classes separated by a single space i.e. <code>first-class second-class</code>'),
'#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : '',
);
}
}
// Only add validation handler once.
if (!isset($form['#validate']) || !in_array('skinr_ui_form_validate', $form['#validate'])) {
$form['#validate'][] = 'skinr_ui_form_validate';
}
// Only add submit handler once.
if (!isset($form['#submit']) || !in_array('skinr_ui_form_submit', $form['#submit'])) {
$form['#submit'][] = 'skinr_ui_form_submit';
}
}
/**
* Form validation handler for skinr_ui_form_alter().
*/
function skinr_ui_form_validate($form, &$form_state) {
$module = $form_state['values']['module'];
$element = $form_state['values']['element'];
$error = FALSE;
if (isset($form_state['values']['skinr_settings'][$module . '_type'])) {
foreach ($form_state['values']['skinr_settings'][$module . '_type'] as $theme_name => $theme) {
if (isset($theme['groups']['_additional']['_additional'])) {
// Validate additional classes field.
if (preg_match('/[^a-zA-Z0-9\-\_\s]/', $theme['groups']['_additional']['_additional'])) {
form_set_error('skinr_settings][' . $module . '_type][' . $theme_name . '][groups][_additional][_additional', t('Additional classes for Skinr may only contain alphanumeric characters, spaces, - and _.'));
$error = TRUE;
}
}
}
}
if (!$error) {
$groups = skinr_get_group_info();
if (isset($form_state['values']['skinr_settings'][$module . '_type'])) {
foreach ($form_state['values']['skinr_settings'][$module . '_type'] as $theme_name => $theme) {
// Unset active tab variables.
foreach ($theme['groups'] as $skin_name => $options) {
if (strpos($skin_name, '__groups__active_tab') !== FALSE) {
unset($form_state['values']['skinr_settings'][$module . '_type'][$theme_name]['groups'][$skin_name]);
continue;
}
}
// Undo any grouping to ease processing on submit.
foreach ($groups as $group_name => $group) {
if (!empty($theme['groups'][$group_name]) && is_array($theme['groups'][$group_name])) {
$group_values = $theme['groups'][$group_name];
unset($form_state['values']['skinr_settings'][$module . '_type'][$theme_name]['groups'][$group_name]);
$form_state['values']['skinr_settings'][$module . '_type'][$theme_name]['groups'] = array_merge($form_state['values']['skinr_settings'][$module . '_type'][$theme_name]['groups'], $group_values);
}
}
}
}
}
}
/**
* Form submission handler for skinr_ui_form_alter().
*/
function skinr_ui_form_submit($form, &$form_state) {
$current_theme = skinr_current_theme(TRUE);
$module = $form_state['values']['module'];
$element = $form_state['values']['element'];
if (isset($form_state['values']['skinr_settings'][$module . '_type'])) {
foreach ($form_state['values']['skinr_settings'][$module . '_type'] as $theme_name => $theme) {
// Process widgets.
if (!empty($theme['groups']) && is_array($theme['groups'])) {
foreach ($theme['groups'] as $skin_name => $options) {
if ($skin_name == '_additional' && !user_access('edit advanced skin settings')) {
// This user doesn't have access to alter these options.
continue;
}
// Ensure options is an array.
if (!is_array($options)) {
$options = $skin_name == '_additional' ? explode(' ', $options) : array($options);
}
// Sanitize options.
$options = _skinr_array_strip_empty($options);
// Find existing skin.
$params = array(
'theme' => $theme_name,
'module' => $module,
'element' => $element,
'skin' => $skin_name,
);
$sids = skinr_skin_get_sids($params);
unset($skin);
if (!empty($sids)) {
$sid = reset($sids);
$skin = skinr_skin_load($sid);
}
if (empty($options)) {
if (!empty($skin)) {
// Delete this skin configuration.
skinr_skin_delete($skin->sid);
}
continue;
}
if (empty($skin)) {
// It doesn't exist, so create a new skin.
$skin = new stdClass();
$skin->theme = $theme_name;
$skin->module = $module;
$skin->element = $element;
$skin->skin = $skin_name;
}
$skin->options = $options;
$skin->status = 1;
// Save skin.
if (!skinr_skin_save($skin)) {
drupal_set_message(t("Skinr settings for %skin weren't saved due to an error.", array('%skin' => $skin_name)), 'error');
}
}
}
}
}
}
/**
* Implements hook_preprocess().
*/
function skinr_ui_preprocess(&$variables, $hook) {
$original_hook = $hook;
$theme_registry = theme_get_registry();
if (isset($theme_registry[$hook]['original hook'])) {
$original_hook = $theme_registry[$hook]['original hook'];
}
$contextual_links = array();
$counter = 0;
$array_elements = skinr_invoke_all('skinr_elements', $variables, $original_hook, 'contextual_links');
foreach ($array_elements as $module => $elements) {
foreach ($elements as $element) {
$contextual_links['skinr-' . $module . '-' . $counter++] = array(
'admin/structure/skinr/edit/nojs', array($module, $element),
);
}
}
if (!empty($contextual_links)) {
skinr_ui_contextual_links($variables, $original_hook, $contextual_links);
}
return;
}
/**
* Set contextual menu items for skinr.
*
* @param $variables
* The $variables parameter from a preprocess function.
* @param $hook
* The $hook parameter from a preprocess function.
* @param $contextual_links
* An array of contextual links data as returned from Skinr's contextual
* links handler.
*/
function skinr_ui_contextual_links(&$variables, $hook, $contextual_links) {
_skinr_ui_set_contextual_links($hook, $contextual_links);
$hooks = theme_get_registry();
// Determine the primary theme function argument.
if (!empty($hooks[$hook]['variables'])) {
$keys = array_keys($hooks[$hook]['variables']);
$key = $keys[0];
}
elseif (!empty($hooks[$hook]['render element'])) {
$key = $hooks[$hook]['render element'];
}
if (!empty($key) && isset($variables[$key])) {
$element = &$variables[$key];
}
if (isset($element) && is_array($element)) {
foreach ($contextual_links as $key => $contextual_link) {
$element['#contextual_links'][$key] = $contextual_link;
}
}
}
/**
* Get all contextual links as returned from Skinr's contextual links handler.
*
* @return
* An array of contextual links data.
*/
function skinr_ui_get_contextual_links() {
return _skinr_ui_set_contextual_links();
}
/**
* Store contextual links internally for future use.
*
* @return
* An array of contextual links data.
*/
function _skinr_ui_set_contextual_links($hook = NULL, $links = NULL) {
static $contextual_links = array();
if ($hook && $links) {
if (!isset($contextual_links[$hook])) {
$contextual_links[$hook] = $links;
}
}
return $contextual_links;
}
/**
* Helper function to determine whether one of a set of hooks exists in a list
* of required theme hooks.
*
* @param $theme_hooks
* An array of theme hooks available to this element.
* @param $allowed_hooks
* An array of allowed theme hooks.
*
* @return
* TRUE if an overlap is found, FALSE otherwise.
*
* @todo Rename function to be more descriptive.
*/
function _skinr_is_featured($theme_hooks, $allowed_hooks) {
foreach ($theme_hooks as $theme_hook) {
if (in_array($theme_hook, $allowed_hooks)) {
return TRUE;
}
}
return FALSE;
}
/**
* Helper function to retrieve a unique id for each skinr class. Used by AJAX.
*
* @return
* A unique ID number.
*
* @todo Evaluate the usefulness of this function. Should it go into
* a UI front-end specific file?
*/
function _skinr_ui_ajax_id() {
static $skinr_id = 0;
return ++$skinr_id;
}
/**
* Helper function to convert an array of options, as specified in the .info
* file, into an array usable by Form API.
*
* @param $options
* An array containing at least the 'class' and 'label' keys.
*
* @return
* A Form API compatible array of options.
*
* @todo Rename function to be more descriptive.
*/
function skinr_ui_info_options_to_form_options($options) {
$form_options = array();
foreach ($options as $option_name => $option) {
$form_options[$option_name] = t($option['title']);
}
return $form_options;
}

View File

@@ -0,0 +1,347 @@
<?php
/**
* @file
* Admin page callbacks for Skinr module's rules.
*/
/**
* Menu callback; displays the skinr rules listing.
*/
function skinr_rules() {
$output = '';
$headers = array(
array('data' => t('Title'), 'field' => 'title'),
array('data' => t('Type'), 'field' => 'type'),
array('data' => t('Operations'), 'colspan' => 2)
);
$rules = skinr_rule_load_multiple();
$rows = array();
foreach ($rules as $rule) {
$row = array(
check_plain($rule->title),
check_plain($rule->rule_type),
l(t('edit'), 'admin/structure/skinr/rules/'. $rule->rid . '/edit'),
l(t('delete'), 'admin/structure/skinr/rules/'. $rule->rid . '/delete'),
);
$rows[] = $row;
}
$link = l(t('Create a new rule'), 'admin/structure/skinr/rules/add');
$row = array();
if (empty($rows)) {
$row[] = array(
'data' => t('No rules have been set up yet. !url.', array('!url' => $link)),
'colspan' => 4,
);
}
else {
$row[] = array(
'data' => t('!url.', array('!url' => $link)),
'colspan' => 4,
);
}
$rows[] = $row;
$output .= theme('table', array('header' => $headers, 'rows' => $rows));
$output .= drupal_render($form);
return $output;
}
/**
* Menu callback; displays the edit form for a skinr rule.
*
* @ingroup forms
*/
function skinr_rule_add($form, &$form_state) {
$form = array();
$form['#tree'] = TRUE;
$form['rule']['title'] = array(
'#type' => 'textfield',
'#title' => t('Title'),
'#default_value' => !empty($form_state['values']['rule']['title']) ? $form_state['values']['rule']['title'] : '',
'#description' => t('Descriptive title for this rule; used by administrators.'),
'#required' => TRUE,
);
$options = array('page' => t('Page'));
foreach (list_themes() as $theme_name => $theme) {
if (empty($theme->status)) {
continue;
}
// Create a list options containing visible regions of this theme.
$regions = array();
foreach (system_region_list($theme_name, REGIONS_VISIBLE) as $region_name => $region) {
$regions['region__' . $region_name] = $region;
}
// Group the list of options by theme.
$key = t('@name Regions', array('@name' => $theme->info['name']));
$options[$key] = $regions;
}
$form['rule']['rule_type'] = array(
'#type' => 'select',
'#title' => t('Type'),
'#options' => $options,
'#default_value' => !empty($form_state['values']['rule']['rule_type']) ? $form_state['values']['rule']['rule_type'] : '',
'#description' => t('Type of element the rule is applied to.'),
'#required' => TRUE,
);
$form['buttons']['save'] = array(
'#type' => 'submit',
'#value' => t('Add'),
);
return $form;
}
/**
* Process skinr_rule_add() submissions.
*/
function skinr_rule_add_submit($form, &$form_state) {
$rule = new stdClass();
$rule->rid = NULL;
$rule->title = $form_state['values']['rule']['title'];
$rule->rule_type = $form_state['values']['rule']['rule_type'];
$rule->node_types = array();
$rule->roles = array();
$rule->visibility = 0;
$rule->pages = '';
skinr_rule_save($rule);
// Set rule id, if we inserted a new rule to allow others to know what rule they're working with.
$form_state['values']['rule']['rid'] = $rule->rid;
$form_state['redirect'] = 'admin/structure/skinr/rules/'. $rule->rid . '/edit';
}
/**
* Form builder for the rule configuration form.
*
* @param $rid
* The rule ID.
*
* @see skinr_rule_edit_submit()
* @ingroup forms
*/
function skinr_rule_edit($form, &$form_state, $rule) {
$form['skinr']['module'] = array(
'#type' => 'hidden',
'#value' => 'rules',
);
$form['skinr']['element'] = array(
'#type' => 'hidden',
'#value' => $rule->rid,
);
$form['rule'] = array(
'#weight' => -1,
);
$form['rule']['rid'] = array(
'#type' => 'value',
'#value' => $rule->rid,
);
$form['rule']['title'] = array(
'#type' => 'textfield',
'#title' => t('Rule title'),
'#default_value' => $rule->title,
'#description' => t('Descriptive title for this rule; used by administrators.'),
'#required' => TRUE,
);
$form['rule']['rule_type'] = array(
'#type' => 'hidden',
'#value' => $rule->rule_type,
);
$form['rule']['rule_type_displayed'] = array(
'#type' => 'item',
'#title' => t('Rule type'),
'#markup' => $rule->rule_type,
'#description' => t('Type of element the rule is applied to.'),
);
// Visibility settings.
$form['visibility_title'] = array(
'#type' => 'item',
'#title' => t('Visibility settings'),
);
$form['visibility'] = array(
'#type' => 'vertical_tabs',
'#attached' => array(
'js' => array(drupal_get_path('module', 'skinr_ui') . '/js/skinr_ui.rules.js'),
),
);
// Per-path visibility.
$form['visibility']['path'] = array(
'#type' => 'fieldset',
'#title' => t('Pages'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'visibility',
'#weight' => 0,
);
$access = user_access('use PHP for settings');
if ($rule->visibility == SKINR_RULE_VISIBILITY_PHP && !$access) {
$form['visibility']['path']['visibility'] = array(
'#type' => 'value',
'#value' => SKINR_RULE_VISIBILITY_PHP,
);
$form['visibility']['path']['pages'] = array(
'#type' => 'value',
'#value' => $rule->pages,
);
}
else {
$options = array(
SKINR_RULE_VISIBILITY_NOTLISTED => t('All pages except those listed'),
SKINR_RULE_VISIBILITY_LISTED => t('Only the listed pages'),
);
$description = t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>'));
if (module_exists('php') && $access) {
$options += array(SKINR_RULE_VISIBILITY_PHP => t('Pages on which this PHP code returns <code>TRUE</code> (experts only)'));
$title = t('Pages or PHP code');
$description .= ' ' . t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', array('%php' => '<?php ?>'));
}
else {
$title = t('Pages');
}
$form['visibility']['path']['visibility'] = array(
'#type' => 'radios',
'#title' => t('Show block on specific pages'),
'#options' => $options,
'#default_value' => $rule->visibility,
);
$form['visibility']['path']['pages'] = array(
'#type' => 'textarea',
'#title' => '<span class="element-invisible">' . $title . '</span>',
'#default_value' => $rule->pages,
'#description' => $description,
);
}
// Per-node visbility.
$form['visibility']['node_type'] = array(
'#type' => 'fieldset',
'#title' => t('Content types'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'visibility',
'#weight' => 5,
);
$form['visibility']['node_type']['types'] = array(
'#type' => 'checkboxes',
'#title' => t('Show block for specific content types'),
'#default_value' => $rule->node_types,
'#options' => node_type_get_names(),
'#description' => t('Show this block only on pages that display content of the given type(s). If you select no types, there will be no type-specific limitation.'),
);
// Per-role visibility.
$role_options = array_map('check_plain', user_roles());
$form['visibility']['role'] = array(
'#type' => 'fieldset',
'#title' => t('Roles'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'visibility',
'#weight' => 10,
);
$form['visibility']['role']['roles'] = array(
'#type' => 'checkboxes',
'#title' => t('Show block for specific roles'),
'#default_value' => $rule->roles,
'#options' => $role_options,
'#description' => t('Show this rule only for the selected role(s). If you select no roles, the rule will be visible to all users.'),
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save rule'),
);
$form['actions']['delete'] = array(
'#type' => 'submit',
'#value' => t('Delete'),
'#submit' => array('skinr_rule_delete_submit'),
);
return $form;
}
/**
* Form submission handler for the rule configuration form.
*
* @see skinr_rule_edit()
*/
function skinr_rule_edit_submit($form, &$form_state) {
$rule = new stdClass();
$rule->rid = !empty($form_state['values']['rid']) ? $form_state['values']['rid'] : NULL;
$rule->rule_type = $form_state['values']['rule_type'];
$rule->title = $form_state['values']['title'];
$rule->node_types = array_filter($form_state['values']['types']);
$rule->roles = $form_state['values']['roles'];
$rule->visibility = (int) $form_state['values']['visibility'];
$rule->pages = trim($form_state['values']['pages']);
skinr_rule_save($rule);
// Set rule id, if we inserted a new rule to allow others to know what rule they're working with.
$form_state['values']['rid'] = $rule->rid;
$form_state['redirect'] = 'admin/structure/skinr/rules';
}
/**
* Called from within the rule edit form; redirects to skinr_rule_delete_confirm().
*
* @ingroup forms
*/
function skinr_rule_delete_submit($form, &$form_state) {
$destination = array();
if (isset($_REQUEST['destination'])) {
$destination = drupal_get_destination();
unset($_REQUEST['destination']);
}
$form_state['redirect'] = array('admin/structure/skinr/rules/' . $form_state['values']['rid'] . 'delete', $destination);
}
/**
* Menu callback; displays the delete confirmation for a skinr rule.
*
* @param $rid
* The rule ID.
*
* @ingroup forms
*/
function skinr_rule_delete_confirm($form, &$form_state, $rule) {
$form['rid'] = array(
'#type' => 'value',
'#value' => $rule->rid,
);
return confirm_form($form,
t('Are you sure you want to delete %title?', array('%title' => $rule->title)),
isset($_GET['destination']) ? $_GET['destination'] : 'admin/structure/skinr/rules',
t('This action cannot be undone.'),
t('Delete'),
t('Cancel')
);
}
/**
* Process skinr_rule_delete_confirm() submissions.
*/
function skinr_rule_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
skinr_rule_delete($form_state['values']['rid']);
}
$form_state['redirect'] = 'admin/structure/skinr/rules';
}

View File

@@ -0,0 +1,830 @@
<?php
/**
* @file
* Tests for the Skinr module.
*/
class SkinrWebTestCase extends DrupalWebTestCase {
/**
* Asserts that a class is set for the given element id.
*
* @param $id
* Id of the HTML element to check.
* @param $class
* The class name to check for.
* @param $message
* Message to display.
* @return
* TRUE on pass, FALSE on fail.
*/
function assertSkinrClass($id, $class, $message = '') {
$elements = $this->xpath('//div[@id=:id and contains(@class, :class)]', array(
':id' => $id,
':class' => $class,
));
$this->assertTrue(!empty($elements[0]), $message);
}
/**
* Asserts that a class is not set for the given element id.
*
* @param $id
* Id of the HTML element to check.
* @param $class
* The class name to check for.
* @param $message
* Message to display.
* @return
* TRUE on pass, FALSE on fail.
*/
function assertNoSkinrClass($id, $class, $message = '') {
$elements = $this->xpath('//div[@id=:id]', array(':id' => $id));
$class_attr = (string) $elements[0]['class'];
$this->assertTrue(strpos($class_attr, $class) === FALSE, $message);
}
}
/**
* Tests basic module installation.
*/
class SkinrInstallationTestCase extends DrupalWebTestCase {
protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'Installation',
'description' => 'Tests basic module installation.',
'group' => 'Skinr',
);
}
function setUp() {
parent::setUp();
}
/**
* Tests installation and uninstallation of Skinr modules.
*/
function testInstallation() {
$this->admin_user = $this->drupalCreateUser(array(
'access administration pages',
'administer modules',
'administer permissions',
));
$this->drupalLogin($this->admin_user);
// Install the modules.
$edit = array(
'modules[Skinr][skinr][enable]' => TRUE,
'modules[Skinr][skinr_ui][enable]' => TRUE,
);
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
// Grant permissions.
$edit = array(
DRUPAL_AUTHENTICATED_RID . '[administer skinr]' => TRUE,
DRUPAL_AUTHENTICATED_RID . '[edit skin settings]' => TRUE,
DRUPAL_AUTHENTICATED_RID . '[edit advanced skin settings]' => TRUE,
);
$this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
// Verify that we are able to access Skinr's administration pages.
$this->drupalGet('admin/structure/skinr');
$this->assertResponse(200);
// Uninstall the modules.
$edit = array(
'modules[Skinr][skinr_ui][enable]' => FALSE,
);
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$edit = array(
'modules[Skinr][skinr][enable]' => FALSE,
);
$this->drupalPost(NULL, $edit, t('Save configuration'));
// Uninstall Skinr UI first.
$edit = array(
'uninstall[skinr_ui]' => TRUE,
);
$this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPost(NULL, array(), t('Uninstall'));
// Now uninstall Skinr.
$edit = array(
'uninstall[skinr]' => TRUE,
);
$this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPost(NULL, array(), t('Uninstall'));
// Verify that no system variables are left.
$count = db_query("SELECT 1 FROM {variable} WHERE name LIKE 'skinr_*'")->fetchField();
$this->assertEqual($count, 0, t('No variables found.'));
}
}
/**
* Tests API functionality.
*
* @link http://drupal.org/node/953336#comment-3738456 Make sure this patch is applied to drupal core @endlink
*/
class SkinrApiTestCase extends SkinrWebTestCase {
protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'API',
'description' => 'Tests Skinr API functionality.',
'group' => 'Skinr',
);
}
public function setUp() {
parent::setUp(array('skinr', 'skinr_test', 'skinr_test_incompatible'));
// Enable skinr_test_subtheme, but NOT the basetheme.
theme_enable(array('skinr_test_subtheme'));
}
/**
* Pass if the message $text was set by one of the CRUD hooks in
* skinr_test.module, i.e., if the $text is an element of
* $_SESSION['skinr_test'].
*
* @param $text
* Plain text to look for.
* @param $message
* Message to display.
* @param $group
* The group this message belongs to, defaults to 'Other'.
* @return
* TRUE on pass, FALSE on fail.
*/
protected function assertHookMessage($text, $message = NULL, $group = 'Other') {
if (!isset($message)) {
$message = $text;
}
return $this->assertTrue(array_search($text, $_SESSION['skinr_test']) !== FALSE, $message, $group);
}
/**
* Tests skinr_implements().
*/
public function testSkinrImplementsAPI() {
// Verify that skinr_implements() only returns extensions that are
// compatible with this version of Skinr.
$extensions = skinr_implements_api();
// The expected extensions and their specific properties, if any.
$all_expected = array(
// Skinr is always expected.
'skinr' => array(),
// Node is a required core module, so always expected.
'node' => array(
'version' => VERSION,
'path' => drupal_get_path('module', 'skinr') . '/modules',
'include file' => drupal_get_path('module', 'skinr') . '/modules/node.skinr.inc',
),
// skinr_test has been installed.
'skinr_test' => array(
'directory' => 'skins',
),
'skinr_test_basetheme' => array(
'type' => 'theme',
'api' => 2,
'directory' => 'skins',
'base themes' => array(),
'sub themes' => drupal_map_assoc(array('skinr_test_subtheme')),
'include file' => drupal_get_path('theme', 'skinr_test_basetheme') . '/skinr_test_basetheme.skinr.inc',
),
'skinr_test_subtheme' => array(
'type' => 'theme',
'api' => 2,
'directory' => 'skins',
'base themes' => drupal_map_assoc(array('skinr_test_basetheme')),
'sub themes' => array(),
'include file' => drupal_get_path('theme', 'skinr_test_subtheme') . '/skinr_test_subtheme.skinr.inc',
),
);
// When running tests on Skinr code packaged by drupal.org, all 'version'
// properties will have the version of the Skinr module. When running on a
// repository checkout, the version is NULL (undefined).
$skinr_module_info = system_get_info('module', 'skinr');
$skinr_module_version = (!empty($skinr_module_info['version']) ? $skinr_module_info['version'] : NULL);
foreach ($all_expected as $name => $expected) {
// Populate defaults.
$expected += array(
'type' => 'module',
'name' => $name,
'version' => $skinr_module_version,
);
$expected += array(
'path' => drupal_get_path($expected['type'], $name),
'directory' => NULL,
);
$this->assertEqual($extensions[$name], $expected, t('%extension implementation found:<pre>@data</pre>', array(
'%extension' => $name,
'@data' => var_export($extensions[$name], TRUE),
)));
unset($extensions[$name]);
}
// Ensure that skinr_test_incompatible is not contained.
$this->assertTrue(!isset($extensions['skinr_test_incompatible']), 'Incompatible extension not found.');
// After asserting all expected, the list of extensions should be empty.
$this->assertTrue(empty($extensions), 'No unexpected extensions found.');
}
/**
* Test module_implements().
*/
function testSkinrImplements() {
// Test clearing cache.
cache_clear_all('skinr_implements', 'cache_bootstrap');
$this->assertFalse(cache_get('skinr_implements', 'cache_bootstrap'), t('The skinr implements cache is empty.'));
$this->drupalGet('');
$this->assertTrue(cache_get('skinr_implements', 'cache_bootstrap'), t('The skinr implements cache is populated after requesting a page.'));
// Test clearing cache with an authenticated user.
$this->user = $this->drupalCreateUser(array());
$this->drupalLogin($this->user);
cache_clear_all('skinr_implements', 'cache_bootstrap');
$this->drupalGet('');
$this->assertTrue(cache_get('skinr_implements', 'cache_bootstrap'), t('The skinr implements cache is populated after requesting a page.'));
// Make sure $module.skinr.inc files (both in the module root, which are
// auto-loaded by drupal, and in custom paths and themes, which are
// loaded by skinr_implements()) are loaded when the hook is called. Also
// ensure only module that implement the current Skinr API are loaded.
$modules = skinr_implements('skinr_skin_info');
// Ensure the hook is found in includes.
$this->assertTrue(in_array('skinr_test', $modules), 'Hook found in $module.skinr.inc file auto-loaded by module_hook().');
$this->assertTrue(in_array('skinr_test_subtheme', $modules), 'Hook found in $module.skinr.inc file in custom path.');
// Ensure that skinr_test_incompatible is not included.
$this->assertTrue(!in_array('skinr_test_incompatible', $modules), 'Hook in incompatible module not found.');
}
/**
* Tests skinr_implements() caching and auto-loading.
*/
function testSkinrImplementsCache() {
module_enable(array('block'));
$this->resetAll();
// Enable main system block for content region and the user menu block for
// the first sidebar.
$default_theme = variable_get('theme_default', 'bartik');
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'system',
'delta' => 'main',
))
->fields(array(
'status' => 1,
'region' => 'content',
'pages' => '',
))
->execute();
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'system',
'delta' => 'powered-by',
))
->fields(array(
'status' => 1,
'region' => 'sidebar_first',
'pages' => '',
))
->execute();
// Enable a skin defined in an include file, which applies to a module
// element that is equally registered in an include file (built-in Block
// module integration).
$skin = (object) array(
'theme' => $default_theme,
'module' => 'block',
'element' => 'system__powered-by',
'skin' => 'skinr_test_font',
'options' => array('font_1'),
'status' => 1,
);
skinr_skin_save($skin);
// Verify the skin is contained in the output.
$this->drupalGet('');
$this->assertSkinrClass('block-system-powered-by', 'font-1', 'Skin found.');
// Once again, so we hit the cache.
$this->drupalGet('');
$this->assertSkinrClass('block-system-powered-by', 'font-1', 'Skin found.');
// Visit skin edit page after to test for groups, after hitting cache.
$this->drupalGet('skinr-test/hook-dynamic-loading');
$this->assertText('success!', t('$module.skinr.inc file auto-loaded.'));
}
/**
* Test that module_invoke_all() can load a hook defined in hook_hook_info().
*/
function testSkinrInvokeAll() {
// Ensure functions from $module.skinr.inc in both module root and in
// custom paths are triggered.
$config_info = skinr_invoke_all('skinr_config_info');
$this->assertTrue(in_array('rules', $config_info), 'Function triggered in $module.skinr.inc file auto-loaded by module_hook().');
$this->assertTrue(in_array('node', $config_info), 'Function triggered in $module.skinr.inc file in custom path.');
// Ensure that skinr_test_incompatible is not included.
$this->assertTrue(!in_array('skinr_test_incompatible', $config_info), 'Function in incompatible module not triggered.');
}
/**
* Tests hook_skinr_skin_info().
*/
public function testSkinrSkinInfo() {
// Verify that skinr_get_skin_info() finds and returns all registered skins
// in $module.skinr.inc files as well as Skinr plugin files, but does not
// return skins that are incompatible with the current Skinr API version.
$skin_info = skinr_get_skin_info();
$path = drupal_get_path('module', 'skinr_test');
// skinr_test_font is registered via hook_skinr_skin_info() in
// skinr_test.skinr.inc.
$this->assertTrue(isset($skin_info['skinr_test_font']), 'Skin registered in $module.skinr.inc found.');
$this->assertEqual($skin_info['skinr_test_font']['source']['path'], $path, t('Skin path points to module directory: @path', array(
'@path' => $skin_info['skinr_test_font']['source']['path'],
)));
unset($skin_info['skinr_test_font']);
// skinr_test_example is registered via hook_skinr_skin_PLUGIN_info() in
// skins/example.inc.
$this->assertTrue(isset($skin_info['skinr_test_example']), 'Skin registered in plugin file found.');
$this->assertEqual($skin_info['skinr_test_example']['source']['path'], $path . '/skins/example', t('Skin path points to plugin directory: @path', array(
'@path' => $skin_info['skinr_test_example']['source']['path'],
)));
unset($skin_info['skinr_test_example']);
// skinr_test_basetheme is registered via hook_skinr_skin_info() in
// skinr_test_basetheme.skinr.inc.
$this->assertTrue(isset($skin_info['skinr_test_basetheme']), 'Skin registered in $basetheme.skinr.inc found.');
$this->assertEqual($skin_info['skinr_test_basetheme']['source']['path'], $path . '/themes/skinr_test_basetheme', t('Skin path points to basetheme directory: @path', array(
'@path' => $skin_info['skinr_test_basetheme']['source']['path'],
)));
$default_theme = variable_get('theme_default', 'bartik');
$this->assertEqual($skin_info['skinr_test_basetheme']['status'][$default_theme], 0, 'Basetheme skin is disabled for default theme.');
$this->assertEqual($skin_info['skinr_test_basetheme']['status']['skinr_test_basetheme'], 1, 'Basetheme skin is enabled for Skinr test basetheme.');
unset($skin_info['skinr_test_basetheme']);
// skinr_test_subtheme is registered via hook_skinr_skin_info() in
// skinr_test_subtheme.skinr.inc.
$this->assertTrue(isset($skin_info['skinr_test_subtheme']), 'Skin registered in $subtheme.skinr.inc found.');
$this->assertEqual($skin_info['skinr_test_subtheme']['source']['path'], $path . '/themes/skinr_test_subtheme', t('Skin path points to subtheme directory: @path', array(
'@path' => $skin_info['skinr_test_subtheme']['source']['path'],
)));
unset($skin_info['skinr_test_subtheme']);
// Ensure that skinr_test_incompatible is not contained.
$this->assertTrue(!isset($skin_info['skinr_test_incompatible']), 'Incompatible skin not found.');
// After asserting all expected, the list of skins should be empty.
$this->assertTrue(empty($skin_info), t('No unexpected skins found: <pre>@data</pre>', array(
'@data' => var_export($skin_info, TRUE),
)));
}
/**
* Tests hook_skinr_group_info().
*/
public function testSkinrGroupInfo() {
$group_info = skinr_get_group_info();
// Verify that default skin groups are found.
$all_expected = array(
'general' => array(
'title' => t('General'),
'weight' => -10,
),
'box' => array(
'title' => t('Box styles'),
),
'typography' => array(
'title' => t('Typography'),
),
'layout' => array(
'title' => t('Layout'),
),
);
foreach ($all_expected as $name => $expected) {
// We don't want to be pixel-perfect here.
if (isset($group_info[$name]['description'])) {
$expected['description'] = $group_info[$name]['description'];
}
$expected += array(
'description' => '',
'weight' => 0,
);
$this->assertEqual($group_info[$name], $expected, t('Group %group found:<pre>@data</pre>', array(
'%group' => $name,
'@data' => var_export($group_info[$name], TRUE),
)));
unset($group_info[$name]);
}
// After asserting all expected, the list of extensions should be empty.
$this->assertTrue(empty($group_info), 'No unexpected groups found.');
}
/**
* Tests hook_skinr_config_info().
*/
public function testSkinrConfigInfo() {
// Verify that skinr_get_config_info() finds all existing and compatible
// hook_skinr_config_info() implementations.
$config = skinr_get_config_info();
// Skinr's own implementation in skinr.skinr.inc should always be found.
$this->assertTrue(in_array('rules', $config), 'hook_skinr_config_info() in $module.skinr.inc found.');
foreach ($config as $key => $type) {
if ($type == 'rules') {
unset($config[$key]);
}
}
// Skinr's implementation on behalf of Node module in modules/node.skinr.inc
// should be found.
$this->assertTrue(in_array('node', $config), 'hook_skinr_config_info() in a custom path found.');
foreach ($config as $key => $type) {
if ($type == 'node') {
unset($config[$key]);
}
}
// Ensure that skinr_test_incompatible is not included.
$this->verbose(highlight_string('<?php ' . var_export($config, TRUE), TRUE));
$this->assertTrue(!isset($config['skinr_test_incompatible']), 'Incompatible hook_skinr_config_info() not found.');
// After asserting all expected, the list of skins should be empty.
$this->assertTrue(empty($config), 'No unexpected skins found.');
}
/**
* Test hook invocations for CRUD operations on skin configurations.
*/
public function testSkinrSkinHooks() {
$skin = (object) array(
'theme' => 'skinr_test_subtheme',
'module' => 'block',
'element' => 'system__user-menu',
'skin' => 'skinr_test_subtheme',
'options' => array('option1', 'option2'),
'status' => 1,
);
$_SESSION['skinr_test'] = array();
skinr_skin_save($skin);
$this->assertHookMessage('skinr_test_skinr_skin_presave called');
$this->assertHookMessage('skinr_test_skinr_skin_insert called');
$_SESSION['skinr_test'] = array();
$skin = skinr_skin_load($skin->sid);
$this->assertHookMessage('skinr_test_skinr_skin_load called');
$_SESSION['skinr_test'] = array();
$skin = skinr_skin_load_unchanged($skin->sid);
$this->assertHookMessage('skinr_test_skinr_skin_load called');
$_SESSION['skinr_test'] = array();
$skin->options = array('option3');
skinr_skin_save($skin);
$this->assertHookMessage('skinr_test_skinr_skin_presave called');
$this->assertHookMessage('skinr_test_skinr_skin_update called');
$_SESSION['skinr_test'] = array();
skinr_skin_delete($skin->sid);
$this->assertHookMessage('skinr_test_skinr_skin_delete called');
}
/**
* Test skinr_skin_save() against invalid entries.
*/
public function testSkinrSkinLoadSave() {
// Only save valid skins.
$skin = (object) array(
'theme' => '',
'module' => 'block',
'element' => 'system__user-menu',
'skin' => 'skinr_test_subtheme',
'options' => array('option1', 'option2'),
'status' => 1,
);
$this->assertFalse(skinr_skin_save($skin), 'Skin configuration object was not saved when $skin->theme was empty.');
$skin->theme = 'skinr_test_subtheme';
$skin->module = '';
$this->assertFalse(skinr_skin_save($skin), 'Skin configuration object was not saved when $skin->module was empty.');
$skin->module = 'block';
$skin->element = '';
$this->assertFalse(skinr_skin_save($skin), 'Skin configuration object was not saved when $skin->element was empty.');
$skin->element = 'system-user-menu';
$skin->skin = '';
$this->assertFalse(skinr_skin_save($skin), 'Skin configuration object was not saved when $skin->skin was empty.');
$skin->skin = 'skinr_test_subtheme';
$skin->options = '';
$this->assertFalse(skinr_skin_save($skin), 'Skin configuration object was not saved when $skin->options was not an array.');
$skin->options = array();
$this->assertFalse(skinr_skin_save($skin), 'Skin configuration object was not saved when $skin->options was an empty array.');
$skin->options = array('option1' => 0, 'option2' => 0);
$this->assertFalse(skinr_skin_save($skin), 'Skin configuration object was not saved when $skin->options was a complex empty array.');
$skin->options = array('option1', 'option2');
$this->assertTrue(skinr_skin_save($skin), 'Skin configuration object was saved.');
$this->assertTrue(isset($skin->sid), 'The sid was added to the skin configuration object.');
// Test loading a skin configuration.
$loaded_skin = skinr_skin_load($skin->sid);
$this->assertTrue(is_array($skin->options), 'Options for the skin configuration object were unserialized.');
$this->assertTrue($loaded_skin->theme == $skin->theme && $loaded_skin->module == $skin->module && $loaded_skin->element == $skin->element && $loaded_skin->status == $skin->status && $loaded_skin->options[0] == $skin->options[0] && $loaded_skin->options[1] == $skin->options[1], 'Skin configuration object was loaded properly.');
// Save a second skin.
$second_skin = (object) array(
'theme' => 'skinr_test_subtheme',
'module' => 'block',
'element' => 'system__main',
'skin' => 'skinr_test_subtheme',
'options' => array('option3'),
'status' => 1,
);
skinr_skin_save($second_skin);
// Test loading multiple skin configurations.
$skins = skinr_skin_load_multiple(array($skin->sid, $second_skin->sid));
$this->assertTrue(count($skins) == 2 && isset($skins[$skin->sid]->sid) && isset($skins[$second_skin->sid]->sid), 'Successfully loaded multiple skins.');
// Test loading all skin configurations.
$skins = skinr_skin_load_multiple();
$this->assertTrue(count($skins) == 2 && isset($skins[$skin->sid]->sid) && isset($skins[$second_skin->sid]->sid), 'Successfully loaded all skins.');
}
}
/**
* Tests API functionality.
*
* @link http://drupal.org/node/953336#comment-3738456 Make sure this patch is applied to drupal core @endlink
*/
class SkinrDisplayTestCase extends SkinrWebTestCase {
protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'Display',
'description' => 'Tests if applied skins appear on the front-end.',
'group' => 'Skinr',
);
}
public function setUp() {
parent::setUp(array('block', 'skinr', 'skinr_test', 'devel'));
$this->admin_user = $this->drupalCreateUser(array(
'administer blocks',
));
$this->drupalLogin($this->admin_user);
// Enable main system block for content region and the user menu block for
// the first sidebar.
// @see http://drupal.org/node/913086
$default_theme = variable_get('theme_default', 'bartik');
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'system',
'delta' => 'main',
))
->fields(array(
'status' => 1,
'region' => 'content',
'pages' => '',
))
->execute();
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'system',
'delta' => 'user-menu',
))
->fields(array(
'status' => 1,
'region' => 'sidebar_first',
'pages' => '',
))
->execute();
// Enable Garland.
theme_enable(array('garland'));
}
public function testSkinrDisplayed() {
// Save a skin configuration object.
$skin = (object) array(
'theme' => 'bartik',
'module' => 'block',
'element' => 'system__user-menu',
'skin' => 'skinr_test_font',
'options' => array('font_1'),
'status' => 1,
);
$this->assertTrue(skinr_skin_save($skin), 'Skin configuration object was saved.');
$this->verbose(print_r($skin, TRUE));
// Go to the front page.
$this->drupalGet('');
$this->assertSkinrClass('block-system-user-menu', 'font-1', 'CSS class of configured skin option found.');
$content = $this->drupalGetContent();
$css = drupal_get_path('module', 'skinr_test') . '/skinr_test.css';
$this->assertRaw($css, t('Stylesheet was included on page.'));
$js = drupal_get_path('module', 'skinr_test') . '/skinr_test.js';
$this->assertRaw($js, t('Javascript was included on page.'));
}
/**
* Tests loading and saving of rules.
*/
public function testSkinrRulesLoadSave() {
// Test saving a rule.
$rule = (object) array(
'title' => 'Rule 1',
'rule_type' => 'page',
'node_types' => array(),
'roles' => array(),
'visibility' => 0, // Show on all pages, except those listed.
'pages' => '',
);
$this->assertTrue(skinr_rule_save($rule), 'Rule object was saved when no filtering is applied.');
$rule->title = '';
$this->assertFalse($status = skinr_rule_save($rule), 'Rule object was not saved when the required $rule->title field was empty.');
$this->pass('Status: ' . ($status ? 'true' : 'false'));
$rule->title = 'Rule 1';
$rule->rule_type = '';
$this->assertFalse(skinr_rule_save($rule), 'Rule object was not saved when the required $rule->rule_type field was empty.');
$rule->rule_type = 'page';
$rule->node_types = FALSE;
$this->assertFalse(skinr_rule_save($rule), 'Rule object was not saved when $rule->node_types was not an array.');
$rule->node_types = array();
$rule->roles = FALSE;
$this->assertFalse(skinr_rule_save($rule), 'Rule object was not saved when $rule->roles was not an array.');
$rule->roles = array();
// Test loading a rule.
$loaded_rule = skinr_rule_load($rule->rid);
$this->assertTrue(is_array($loaded_rule->node_types), 'Node types for the rule object were unserialized.');
$this->assertTrue(is_array($loaded_rule->roles), 'Roles for the rule object were unserialized.');
$this->assertTrue($loaded_rule->title == $rule->title && $loaded_rule->rule_type == $rule->rule_type && $loaded_rule->node_types == $rule->node_types && $loaded_rule->roles == $rule->roles && $loaded_rule->visibility == $rule->visibility && $loaded_rule->pages == $rule->pages, 'Rule object was loaded properly.');
// Save a second rule.
$second_rule = (object) array(
'title' => 'Rule 2',
'rule_type' => 'page',
'node_types' => array(),
'roles' => array(),
'visibility' => 0, // Show on all pages, except those listed.
'pages' => '',
);
skinr_rule_save($second_rule);
// Test loading multiple skin configurations.
$rules = skinr_rule_load_multiple(array($rule->rid, $second_rule->rid));
$this->assertTrue(count($rules) == 2 && isset($rules[$rule->rid]->rid) && isset($rules[$second_rule->rid]->rid), 'Successfully loaded multiple rules.');
// Test loading all skin configurations.
$rules = skinr_rule_load_multiple();
$this->assertTrue(count($rules) == 2 && isset($rules[$rule->rid]->rid) && isset($rules[$second_rule->rid]->rid), 'Successfully loaded all rules.');
}
}
/**
* Tests API functionality.
*/
class SkinrRulesApiTestCase extends DrupalWebTestCase {
// @todo Requires http://drupal.org/node/913086
// protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'Rules API',
'description' => 'Tests Skinr Rules API functionality.',
'group' => 'Skinr',
);
}
function setUp() {
parent::setUp(array('skinr', 'php'));
// Set up some nodes.
$this->article = $this->drupalCreateNode(array(
'type' => 'article',
'title' => 'Article node',
));
$this->page = $this->drupalCreateNode(array(
'type' => 'page',
'title' => 'Page node',
));
// Set up some users.
$this->web_user = $this->drupalCreateUser(array());
}
/**
* Tests visibility of rules.
*/
public function testSkinrRulesVisibility() {
global $user;
$front = variable_get('site_frontpage', 'node');
$rule = (object) array(
'title' => 'Rule 1',
'rule_type' => 'page',
'node_types' => array(),
'roles' => array(),
'visibility' => 0, // Show on all pages, except those listed.
'pages' => '',
);
skinr_rule_save($rule);
// Test visibility when no filters are applied.
$this->assertTrue(skinr_rule_is_visible($rule->rid, $front), 'Rule is visible on front page.');
$this->assertTrue(skinr_rule_is_visible($rule->rid, 'node/' . $this->article->nid), 'Rule is visible on an article node page.');
$this->assertTrue(skinr_rule_is_visible($rule->rid, 'node/' . $this->page->nid), 'Rule is visible on a basic page node.');
// Test visibility with a node type filter.
$rule->node_types = array('article' => 'article');
skinr_rule_save($rule);
$this->assertFalse(skinr_rule_is_visible($rule->rid, $front), 'Node type limited rule is not visible on front page.');
$this->assertTrue(skinr_rule_is_visible($rule->rid, 'node/' . $this->article->nid), 'Node type limited rule is visible on the node type.');
$this->assertFalse(skinr_rule_is_visible($rule->rid, 'node/' . $this->page->nid), 'Node type limited rule is not visible on a different node type.');
// Verify visibility on node/add/* paths.
$this->assertTrue(skinr_rule_is_visible($rule->rid, 'node/add/article'), 'Node type limited rule is visible on the node type add page.');
$this->assertFalse(skinr_rule_is_visible($rule->rid, 'node/add/page'), 'Node type limited rule is not visible on a different node type add page.');
// Test visibility with a roles filter.
$rule->node_types = array();
$rule->roles = array(DRUPAL_AUTHENTICATED_RID => DRUPAL_AUTHENTICATED_RID);
skinr_rule_save($rule);
$user = $this->web_user;
$this->assertTrue(skinr_rule_is_visible($rule->rid, $front), 'Role limited rule is visible for authenticated users.');
$user = drupal_anonymous_user();
$this->assertFalse(skinr_rule_is_visible($rule->rid, $front), 'Role limited rule is not visible for anonymous users.');
// Test visibility with an exclude page filter.
$rule->roles = array();
$rule->pages = "<front>";
skinr_rule_save($rule);
$this->assertFalse(skinr_rule_is_visible($rule->rid, $front), 'Path excluded rule is not visible on excluded path.');
$this->assertTrue(skinr_rule_is_visible($rule->rid, 'node/' . $this->article->nid), 'Path excluded rule is visible on not excluded path.');
// Test visibility with an include page filter.
$rule->visibility = 1;
skinr_rule_save($rule);
$this->assertTrue(skinr_rule_is_visible($rule->rid, $front), 'Path limited rule is visible on included path.');
$this->assertFalse(skinr_rule_is_visible($rule->rid, 'node/' . $this->article->nid), 'Path limited rule is not visible on different path.');
// Test visibility with a PHP page filter.
$rule->visibility = 2;
$rule->pages = '<?php
return FALSE;
?>';
skinr_rule_save($rule);
$this->assertFalse(skinr_rule_is_visible($rule->rid, $front), 'PHP disabled rule is not visible on front page.');
$this->assertFalse(skinr_rule_is_visible($rule->rid, 'node/' . $this->article->nid), 'PHP disabled rule is not visible on node type page.');
$rule->pages = '<?php
return TRUE;
?>';
skinr_rule_save($rule);
$this->assertTrue(skinr_rule_is_visible($rule->rid), 'PHP enabled rule is visible on front page.');
$this->assertTrue(skinr_rule_is_visible($rule->rid, 'node/' . $this->article->nid), 'PHP enabled rule is visible on node type page.');
}
}

View File

@@ -0,0 +1,2 @@
.font-1 { font-family: Arial, Helvetica, "Nimbus Sans L", "Liberation Sans", "FreeSans", sans-serif; }
.font-2 { font-family: "Lucida Grande", "Lucida Sans Unicode", "DejaVu Sans", Arial, sans-serif; }

View File

@@ -0,0 +1,13 @@
name = Skinr Testing
description = A test module used for testing Skinr.
package = Testing
core = 7.x
hidden = TRUE
dependencies[] = skinr
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,3 @@
/**
* Non-functional JS file to test for inclusion on page.
*/

View File

@@ -0,0 +1,104 @@
<?php
/**
* @file
* Skinr testing module.
*
* Other modules should be able to place their Skinr support/integration code
* into a conditionally loaded $module.skinr.inc file, so this .module file
* only exists, because Drupal requires a .module file to exist.
*/
/**
* Implements hook_menu().
*/
function skinr_test_menu() {
$items['skinr-test/hook-dynamic-loading'] = array(
'title' => 'Test hook dynamic loading (skinr_hook)',
'page callback' => 'skinr_test_hook_dynamic_loading',
'access arguments' => array('access content'),
);
return $items;
}
/**
* Page callback for 'hook dynamic loading' test.
*
* If the hook is dynamically loaded correctly, the menu callback should
* return 'success!'.
*/
function skinr_test_hook_dynamic_loading() {
if (skinr_hook('skinr_test', 'skinr_group_info') && function_exists('skinr_test_skinr_group_info')) {
return 'success!';
}
return 'failed!';
}
/**
* Implements hook_system_theme_info().
*
* @see http://drupal.org/node/953336
*/
function skinr_test_system_theme_info() {
$path = drupal_get_path('module', 'skinr_test');
$test_themes = array('basetheme', 'subtheme', 'basetheme_other', 'subtheme_other');
foreach ($test_themes as $theme) {
$themes["skinr_test_{$theme}"] = $path . "/themes/skinr_test_{$theme}/skinr_test_{$theme}.info";
}
return $themes;
}
//
// Presave hooks
//
/**
* Implements hook_skinr_skin_presave().
*/
function skinr_test_skinr_skin_presave() {
$_SESSION['skinr_test'][] = (__FUNCTION__ . ' called');
}
//
// Insert hooks
//
/**
* Implements hook_skinr_skin_insert().
*/
function skinr_test_skinr_skin_insert() {
$_SESSION['skinr_test'][] = (__FUNCTION__ . ' called');
}
//
// Load hooks
//
/**
* Implements hook_skinr_skin_load().
*/
function skinr_test_skinr_skin_load() {
$_SESSION['skinr_test'][] = (__FUNCTION__ . ' called');
}
//
// Update hooks
//
/**
* Implements hook_skinr_skin_update().
*/
function skinr_test_skinr_skin_update() {
$_SESSION['skinr_test'][] = (__FUNCTION__ . ' called');
}
//
// Delete hooks
//
/**
* Implements hook_skinr_skin_delete().
*/
function skinr_test_skinr_skin_delete() {
$_SESSION['skinr_test'][] = (__FUNCTION__ . ' called');
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Implements hook_skinr_api_VERSION().
*/
function skinr_test_skinr_api_2() {
return array(
'directory' => 'skins',
);
}
/**
* Implements hook_skinr_group_info().
*/
function skinr_test_skinr_group_info() {
$groups['skinr_test'] = array(
'title' => t('skinr_test'),
);
}
/**
* Implements hook_skinr_skin_info().
*/
function skinr_test_skinr_skin_info() {
$skins['skinr_test_font'] = array(
'title' => t('Font family'),
'type' => 'select',
'group' => 'typography',
'theme hooks' => array('block', 'region'),
'default status' => 1,
'attached' => array(
'css' => array('skinr_test.css'),
'js' => array('skinr_test.js'),
),
'options' => array(
'font_1' => array(
'title' => 'Arial, Helvetica, Nimbus Sans L, Liberation Sans, FreeSans',
'class' => array('font-1'),
),
'font_2' => array(
'title' => 'Lucida Grande, Lucida Sans Unicode, DejaVu Sans, Tahoma',
'class' => array('font-2'),
),
),
);
return $skins;
}

View File

@@ -0,0 +1,11 @@
<?php
/**
* Implements hook_skinr_skin_PLUGIN_info().
*/
function skinr_test_skinr_skin_example_info() {
$skins['skinr_test_example'] = array(
'title' => t('Example skin plugin'),
);
return $skins;
}

View File

@@ -0,0 +1,13 @@
name = Skinr test base theme
description = Test theme which acts as a base theme for other test subthemes.
core = 7.x
hidden = TRUE
skinr[api] = 2
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,15 @@
<?php
/**
* Implements hook_skinr_skin_info().
*/
function skinr_test_basetheme_skinr_skin_info() {
$skins['skinr_test_basetheme'] = array(
'title' => 'Base theme skin',
'default status' => 0,
'status' => array(
'skinr_test_basetheme' => 1,
),
);
return $skins;
}

View File

@@ -0,0 +1,11 @@
name = Skinr test base theme (other)
description = Test theme which acts as a normal base theme for other test subthemes. It does not include any skins.
core = 7.x
hidden = TRUE
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,12 @@
<?php
/**
* Implements hook_skinr_skin_info().
*/
function skinr_test_basetheme_other_skinr_skin_info() {
$skins['skinr_test_basetheme_other'] = array(
'title' => 'Other base theme skin',
'default status' => 1,
);
return $skins;
}

View File

@@ -0,0 +1,14 @@
name = Skinr test subtheme
description = Test theme which uses skinr_test_basetheme as the base theme.
core = 7.x
base theme = skinr_test_basetheme
hidden = TRUE
skinr[api] = 2
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,12 @@
<?php
/**
* Implements hook_skinr_skin_info().
*/
function skinr_test_subtheme_skinr_skin_info() {
$skins['skinr_test_subtheme'] = array(
'title' => 'Subtheme skin',
'default status' => 1,
);
return $skins;
}

View File

@@ -0,0 +1,12 @@
name = Skinr test subtheme (other)
description = Test theme which uses skinr_test_basetheme_other as the base theme. Neither include any skins.
core = 7.x
base theme = skinr_test_basetheme_other
hidden = TRUE
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,12 @@
<?php
/**
* Implements hook_skinr_skin_info().
*/
function skinr_test_subtheme_other_skinr_skin_info() {
$skins['skinr_test_subtheme_other'] = array(
'title' => 'Other subtheme skin',
'default status' => 1,
);
return $skins;
}

View File

@@ -0,0 +1,13 @@
name = Skinr Incompatible Testing
description = A test module used for testing incompatible Skinr API implementations.
package = Testing
core = 7.x
hidden = TRUE
dependencies[] = skinr
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,34 @@
<?php
/**
* Implements hook_skinr_api(). (bogus)
*/
function skinr_test_incompatible_skinr_api() {
}
/**
* Implements hook_skinr_api_VERSION(). (incompatible)
*/
function skinr_test_incompatible_skinr_api_1() {
}
/**
* Implements hook_skinr_skin_info().
*
* This hook implementation purposively does not live in $module.skinr.inc, so
* tests can verify that this implementation is not invoked, even though it is
* loaded.
*/
function skinr_test_incompatible_skinr_skin_info() {
$skins['skinr_test_incompatible'] = array(
'title' => 'Incompatible',
);
return $skins;
}
/**
* Implements hook_skinr_config_info().
*/
function skinr_test_incompatible_skinr_config_info() {
return array('skinr_test_incompatible');
}

View File

@@ -0,0 +1,556 @@
<?php
/**
* @file
* Tests for the Skinr UI module.
*/
/**
* Base class for Skinr UI tests.
*/
class SkinrUITestCase extends DrupalWebTestCase {
protected $profile = 'testing';
function setUp() {
$modules = func_get_args();
if (isset($modules[0]) && is_array($modules[0])) {
$modules = $modules[0];
}
parent::setUp(array_merge(array('block', 'comment', 'contextual', 'skinr_ui', 'skinr_ui_test'), $modules));
$this->admin_user = $this->drupalCreateUser(array(
'administer blocks',
'access contextual links',
'administer skinr',
'edit skin settings',
'edit advanced skin settings',
));
$this->drupalLogin($this->admin_user);
// Enable main system block for content region and the user menu block for
// the first sidebar.
// @see http://drupal.org/node/913086
$default_theme = variable_get('theme_default', 'bartik');
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'system',
'delta' => 'main',
))
->fields(array(
'status' => 1,
'region' => 'content',
'pages' => '',
))
->execute();
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'system',
'delta' => 'user-menu',
))
->fields(array(
'status' => 1,
'region' => 'sidebar_first',
'pages' => '',
))
->execute();
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'search',
'delta' => 'form',
))
->fields(array(
'status' => 1,
'region' => 'sidebar_first',
'pages' => '',
))
->execute();
}
/**
* Asserts that a class is set for the given element id.
*
* @param $id
* Id of the HTML element to check.
* @param $class
* The class name to check for.
* @param $message
* Message to display.
* @return
* TRUE on pass, FALSE on fail.
*/
function assertSkinrClass($id, $class, $message = '') {
$elements = $this->xpath('//div[@id=:id]', array(':id' => $id));
$class_attr = (string) $elements[0]['class'];
$this->assertTrue(strpos($class_attr, ' ' . $class . ' '), $message);
}
/**
* Asserts that a class is not set for the given element id.
*
* @param $id
* Id of the HTML element to check.
* @param $class
* The class name to check for.
* @param $message
* Message to display.
* @return
* TRUE on pass, FALSE on fail.
*/
function assertNoSkinrClass($id, $class, $message = '') {
$elements = $this->xpath('//div[@id=:id]', array(':id' => $id));
$class_attr = (string) $elements[0]['class'];
$this->assertFalse(strpos($class_attr, ' ' . $class . ' '), $message);
}
}
/**
* Tests UI functionality.
*/
class SkinrUIBasicTestCase extends SkinrUITestCase {
public static function getInfo() {
return array(
'name' => 'UI',
'description' => 'Tests basic Skinr UI functionality.',
'group' => 'Skinr',
);
}
/**
* Tests basic configuration and applying of a skin.
*
* @todo For some reason, contextual links are not visible in the debug output
* when running tests; likely a core bug in contextual.js. However, the
* links are contained in the output. Keep this in mind when manually
* reviewing the debug output after running tests!
* @todo Remove the overly verbose inline comments after the Skinr development
* team has figured out how to write tests.
*/
function testSkinEdit() {
// Go to the front page, on which the user menu block should appear.
$this->drupalGet('');
// Click the first (index 0) 'Edit skin' link on the page, which should be
// the link in the contextual links of the user menu block, since no other
// skinnable elements are visible on the page.
// For now, this is a simple way to assert and access Skinr links. In the
// future, we want to be more explicit in testing; i.e., verify that there
// is really only this link, its 'href' is correct, that it appears in the
// right location, etc.pp; DrupalWebTestCase ($this) provides many helper
// functions to assert such things.
$this->clickLink(t('Edit skin'), 0);
// Verify that we end up on the expected URL to configure skins for the
// user menu block.
$front = variable_get('site_frontpage', 'node');
$this->assertUrl('admin/structure/skinr/edit/nojs/block/system__user-menu/configure', array(
'query' => array('destination' => $front),
));
// skinr_ui_test.module got enabled in setUp(), so its skins should be
// available.
// Verify that we can apply the skinr_ui_test_border skin to the block.
$edit = array(
'skinr_settings[block_type][bartik][groups][general][skinr_ui_test_bgcolor]' => 'bgcolor_red',
);
// NULL means that we want to post to the page that is still contained in
// SimpleTest's internal browser; i.e., the page of the path above. Instead
// of passing NULL, you can also pass a Drupal system path and SimpleTest
// will automatically do a $this->drupalGet($path) for you before posting.
$this->drupalPost(NULL, $edit, t('Save'));
// After posting, we expect to be redirected to the originating page, due
// to the 'destination' query parameter in the 'Edit skin' link. Since we
// came from the front page, Drupal will redirect us to the actual path of
// the front page, not ''.
// Verify that we were redirected to the originating page.
$this->assertUrl($front);
// Verify that the skin has been applied.
$this->assertSkinrClass('block-system-user-menu', 'bgcolor-red', 'CSS class of configured skin option found.');
}
/**
* Tests access control for editing additional CSS classes.
*/
function testSkinAdditionalEdit() {
// Verify that we can apply additional CSS classes.
$edit = array(
'skinr_settings[block_type][bartik][groups][_additional][_additional]' => 'additional',
);
$this->drupalPost('admin/structure/skinr/edit/nojs/block/system__user-menu/configure', $edit, t('Save'));
// Verify that the skin has been applied.
$this->drupalGet('');
$this->assertSkinrClass('block-system-user-menu', 'additional', 'Additional CSS class <em>additional</em> of configured skin option found.');
// Now let's check the same for a user that has no access to alter this.
$user = $this->drupalCreateUser(array('edit skin settings'));
$this->drupalLogin($user);
// Verify that the additional CSS classes field is not enabled.
$this->drupalGet('admin/structure/skinr/edit/nojs/block/system__user-menu/configure');
$this->assertNoFieldByName('skinr_settings[block_type][bartik][groups][_additional][_additional]', NULL, 'Additional CSS classes field is not enabled for this user.');
// Save form when additional CSS classes is not set.
$edit = array();
$this->drupalPost(NULL, $edit, t('Save'));
// Verify that the old class is still applied.
$this->drupalGet('');
$this->assertSkinrClass('block-system-user-menu', 'additional', 'Additional CSS class <em>additional</em> of configured skin option found.');
}
/**
* Tests output of widgets on the skin configuration form.
*/
function testSkinEditWidgets() {
// Go to the edit page for system__user_menu block.
$this->drupalGet('admin/structure/skinr/library');
$this->drupalGet('admin/structure/skinr/edit/nojs/block/system__user-menu/configure');
// Check the widgets.
$this->assertFieldByName('skinr_settings[block_type][bartik][groups][general][skinr_ui_test_bgcolor]', NULL, 'Widget with valid type is displayed.');
$this->assertNoFieldByName('skinr_settings[block_type][bartik][groups][box][skinr_ui_test_border]', NULL, 'Widget with invalid type is not displayed.');
$this->assertFieldByName('skinr_settings[block_type][bartik][groups][general][skinr_ui_test_custom][custom]', NULL, 'Widget with form callback is displayed.');
// Check for output from empty groups.
$this->assertNoRaw('id="edit-skinr-settings-block-group-bartik-box"', 'Resulting empty group is not displayed.');
}
/**
* Tests access control for editing additional CSS classes.
*/
function testSkinEditThemeHooks() {
// Widget should appear for system blocks.
$this->drupalGet('admin/structure/skinr/edit/nojs/block/system__user-menu/configure');
$this->assertField('edit-skinr-settings-block-type-bartik-groups-general-skinr-ui-test-color-color-white', 'The widget, which is limited to system blocks, appeared on the configuration form for system\'s user-menu block.');
// Widget should not appear search blocks.
$this->drupalGet('admin/structure/skinr/edit/nojs/block/search__form/configure');
$this->assertNoField('edit-skinr-settings-block-type-bartik-groups-general-skinr-ui-test-color-color-white', 'The widget, which is limited to system blocks, did not appear on the configuration form for search\'s form block.');
// Widget should appear for page node comments.
$this->drupalGet('admin/structure/skinr/edit/nojs/comment/page/configure');
$this->assertField('edit-skinr-settings-comment-type-bartik-groups-general-skinr-ui-test-color-color-white', 'The widget, which is limited to page node comments, appeared on the configuration form for page node comments.');
// Widget should not appear for article node comments.
$this->drupalGet('admin/structure/skinr/edit/nojs/comment/article/configure');
$this->assertNoField('edit-skinr-settings-comment-type-bartik-groups-general-skinr-ui-test-color-color-white', 'The widget, which is limited to page node comments, did not appear on the configuration form for article node comments.');
// Widget should appear for page nodes.
$this->drupalGet('admin/structure/skinr/edit/nojs/node/page/configure');
$this->assertField('edit-skinr-settings-node-type-bartik-groups-general-skinr-ui-test-color-color-white', 'The widget, which is limited to page node types, appeared on the configuration form for page node types.');
// Widget should not appear for article nodes.
$this->drupalGet('admin/structure/skinr/edit/nojs/node/article/configure');
$this->assertNoField('edit-skinr-settings-node-type-bartik-groups-general-skinr-ui-test-color-color-white', 'The widget, which is limited to page node types, did not appear on the configuration form for article node types.');
}
}
/**
* Tests administrative pages functionality.
*/
class SkinrUIAdminTestCase extends SkinrUITestCase {
public static function getInfo() {
return array(
'name' => 'Administration',
'description' => 'Tests administrative Skinr UI functionality.',
'group' => 'Skinr',
);
}
function setUp() {
parent::setUp(array('skinr_test'));
$this->admin_user = $this->drupalCreateUser(array(
'administer skinr',
'edit skin settings',
'edit advanced skin settings',
));
$this->drupalLogin($this->admin_user);
// Enable Garland and skinr_test_subtheme without enabling its base theme in
// order to test subtheme inheritance functionality.
theme_enable(array('garland', 'skinr_test_subtheme'));
}
/**
* Tests default status of skins.
*
* The skinr_test_basetheme skin defined by the skinr_test_basetheme theme
* specifies a default status for itself. Its subtheme should inherit the
* status of the basetheme.
*
* @todo Add assertions for 'default status' itself.
*/
function testSkinDefaultStatus() {
// Verify that it is enabled for the skinr_test_subtheme.
$this->drupalGet('admin/structure/skinr/library/list/skinr_test_subtheme');
$this->assertFieldChecked('edit-skins-general-skinr-test-basetheme-enable', 'skinr_test_basetheme skin is enabled for skinr_test_subtheme.');
// Verify that it is disabled for Bartik by default.
$this->drupalGet('admin/structure/skinr/library/list/bartik');
$this->assertNoFieldChecked('edit-skins-general-skinr-test-basetheme-enable', 'skinr_test_basetheme skin is disabled for Bartik.');
// Verify that it is disabled for Garland by default.
$this->drupalGet('admin/structure/skinr/library/list/garland');
$this->assertNoFieldChecked('edit-skins-general-skinr-test-basetheme-enable', 'skinr_test_basetheme skin is disabled for Garland.');
// Override the status for skinr_test_subtheme and Bartik, then verify them.
$skin = (object) array(
'theme' => 'skinr_test_subtheme',
'module' => 'block',
'element' => 'system-user-menu',
'skin' => 'skinr_test_subtheme',
'options' => array('option1', 'option2'),
'status' => 1,
);
skinr_skin_save($skin);
$skin = skinr_skin_load($skin->sid);
// Override the default skin.
$skin->element = 'system-main';
$this->drupalGet('admin/structure/skinr');
$this->clickLink(t('disable'), 0);
// Unaltered skin configuration object should have been saved with only the status updated.
// Load an uncached version of the skin configuration object.
$skin = skinr_skin_load_unchanged($skin->sid);
$this->assertFalse($skin->status, 'Status was disabled successfully.');
$this->assertEqual($skin->element, 'system-user-menu', 'Only status was updated, even though the object was modified before updating status.');
// Enable the skin configuration.
$this->drupalGet('admin/structure/skinr');
$this->clickLink(t('enable'), 0);
// Load an uncached version of the skin configuration object.
$skin = skinr_skin_load_unchanged($skin->sid);
$this->assertTrue($skin->status, 'Status was enabled successfully.');
}
/**
* Tests skin group functionality.
*/
function testSkinGroups() {
$this->drupalGet('admin/structure/skinr/library');
// Verify that the 'General' (default) group appears.
$this->assertText(t('General'));
// Verify that the 'Box styles' group appears, since skinr_ui_test module
// registers a skin in that group.
$this->assertText(t('Box styles'));
}
/**
* Tests skin configuration listing functionality.
*/
function testSkinListing() {
$skin = (object) array(
'theme' => 'skinr_test_subtheme',
'module' => 'block',
'element' => 'system__user-menu',
'skin' => 'skinr_test_subtheme',
'options' => array('option1', 'option2'),
'status' => 1,
);
skinr_skin_save($skin);
// Verify that the skin configuration appears on the skin configurations overview page.
$this->drupalGet('admin/structure/skinr');
$this->assertLinkByHref('admin/structure/skinr/skin/' . $skin->sid . '/delete?destination=admin/structure/skinr', 0, 'Skin configuration was found on overview page.');
// @todo Should we check the filtering and update options functionality?
}
}
/**
* Tests rules administrative pages functionality.
*/
class SkinrUIRulesTestCase extends SkinrUITestCase {
public static function getInfo() {
return array(
'name' => 'Rules UI',
'description' => 'Tests rules functionality for Skinr UI.',
'group' => 'Skinr',
);
}
/**
* Tests administrative interface for rules.
*/
function testRules() {
// Test that there is a rules page.
$this->drupalGet('admin/structure/skinr');
$this->assertLinkByHref('admin/structure/skinr/rules');
// Test that there is a way to add rules.
$this->drupalGet('admin/structure/skinr/rules');
$this->clickLink(t('Create a new rule'), 0);
// Verify that we end up on the expected URL.
$this->assertUrl('admin/structure/skinr/rules/add');
// Verify that we can create the rule.
$edit = array(
'rule[title]' => 'Rule 1',
'rule[rule_type]' => 'page',
);
$this->drupalPost(NULL, $edit, t('Add'));
// After posting, we expect to be redirected to the rule edit page.
$this->assertUrl('admin/structure/skinr/rules/1/edit');
// Save rule.
// @todo Add a skin and test whether it applies properly or not.
$edit = array(
);
$this->drupalPost(NULL, $edit, t('Save rule'));
// We should be returned back to the rules page.
$this->assertUrl('admin/structure/skinr/rules');
// Make sure the new rule appears listed on this page.
$this->assertLinkByHref('admin/structure/skinr/rules/1/edit');
}
}
/**
* Tests UI functionality for Block plugin.
*/
class SkinrUIPluginTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Plugins UI - Core',
'description' => 'Tests Skinr UI functionality for functionality plugins from Drupal core.',
'group' => 'Skinr',
);
}
function setUp() {
parent::setUp(array('block', 'comment', 'node', 'skinr_ui'));
$this->admin_user = $this->drupalCreateUser(array(
'administer blocks',
'access comments',
'access content',
'post comments',
'skip comment approval',
'access contextual links',
'administer skinr',
'edit skin settings',
'edit advanced skin settings',
'bypass node access',
));
$this->drupalLogin($this->admin_user);
}
/**
* Tests block plugin.
*/
function testBlock() {
// Enable user menu block for the first sidebar.
// @see http://drupal.org/node/913086
$default_theme = variable_get('theme_default', 'bartik');
db_merge('block')
->key(array(
'theme' => $default_theme,
'module' => 'system',
'delta' => 'user-menu',
))
->fields(array(
'status' => 1,
'region' => 'sidebar_first',
'pages' => '',
))
->execute();
// Get front page.
$this->drupalGet('');
// Make sure our contextual link appears on the page.
$this->assertLinkByHref('admin/structure/skinr/edit/nojs/block/system__user-menu/configure', 0, 'Contexual link to edit block\'s skin configuration was found.');
}
/**
* Tests comment plugin.
*/
function testComment() {
// Create a node.
$node1 = $this->drupalCreateNode(array('type' => 'article'));
// Go to node.
$uri = entity_uri('node', $node1);
$this->drupalGet($uri['path']);
// Add a comment to the node. With bartik the contextual links won't
// display until there is at least one comment.
$edit = array(
'comment_body[und][0][value]' => $this->randomString(128),
);
$this->drupalPost(NULL, $edit, t('Save'));
// Make sure our contextual link appears on the page.
$this->assertLinkByHref('admin/structure/skinr/edit/nojs/comment/article/configure', 0, 'Contexual link to edit comment\'s skin configuration was found.');
}
/**
* Tests node plugin.
*/
function testNode() {
// Create a node.
$node = $this->drupalCreateNode(array('type' => 'article'));
// Go to node.
$uri = entity_uri('node', $node);
$this->drupalGet($uri['path']);
// Make sure our contextual link appears on the page.
$this->assertLinkByHref('admin/structure/skinr/edit/nojs/node/article/configure', 0, 'Contexual link to edit node\'s skin configuration was found.');
}
}
/**
* Tests UI functionality for Block plugin.
*/
/**
* Tests UI functionality for Block plugin.
*/
class SkinrUIPluginViewsTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Plugins UI - Views',
'description' => 'Tests Skinr UI functionality for functionality plugin from Views.',
'dependencies' => array('views', 'views_ui'),
'group' => 'Skinr',
);
}
function setUp() {
parent::setUp(array('views_ui', 'skinr_ui_test'));
$this->admin_user = $this->drupalCreateUser(array(
'administer views',
'access all views',
'access contextual links',
'administer skinr',
'edit skin settings',
'edit advanced skin settings',
));
$this->drupalLogin($this->admin_user);
}
/**
* Tests views plugin.
*/
function testViews() {
// Go to the view's page.
$this->drupalGet('skinr-ui-test-view');
// Make sure our contextual link appears on the page.
$this->assertLinkByHref('admin/structure/skinr/edit/nojs/views/skinr_ui_test__page/configure', 0, "Contexual link to edit view's skin configuration was found.");
}
}

View File

@@ -0,0 +1,13 @@
name = Skinr UI Testing
description = A test module used for testing Skinr UI.
package = Testing
core = 7.x
hidden = TRUE
dependencies[] = skinr_ui
; Information added by drupal.org packaging script on 2012-01-20
version = "7.x-2.0-alpha1"
core = "7.x"
project = "skinr"
datestamp = "1327086045"

View File

@@ -0,0 +1,13 @@
<?php
/**
* @file
* Skinr UI testing module.
*/
/**
* Implementation of hook_views_api().
*/
function skinr_ui_test_views_api() {
return array('api' => 3);
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Implements hook_skinr_api_VERSION().
*/
function skinr_ui_test_skinr_api_2() {
return array(
'directory' => 'skins',
);
}
/**
* Implements hook_skinr_skin_info().
*/
function skinr_ui_test_skinr_skin_info() {
$skins['skinr_ui_test_bgcolor'] = array(
'title' => t('Background color'),
'type' => 'select',
'group' => 'general',
'default status' => 1,
'options' => array(
'bgcolor_red' => array(
'title' => 'Red',
'class' => array('bgcolor-red'),
),
),
);
$skins['skinr_ui_test_border'] = array(
'title' => t('Border'),
// Use an invalid type name.
'type' => 'invalid',
// Use a different group than the skin before to test for output of an empty group.
'group' => 'box',
'default status' => 1,
'options' => array(
'border_1' => array(
'title' => 'Thin border',
'class' => array('border-1'),
),
),
);
$skins['skinr_ui_test_color'] = array(
'title' => t('Color'),
'type' => 'checkboxes',
'group' => 'general',
'theme hooks' => array('block__system', 'comment_wrapper__page', 'node__page'),
'default status' => 1,
'options' => array(
'color_white' => array(
'title' => 'White',
'class' => array('color-white'),
),
),
);
$skins['skinr_ui_test_custom'] = array(
'title' => t('Custom'),
'form callback' => 'skinr_ui_test_skinr_skinr_ui_test_custom_form',
'group' => 'general',
'theme hooks' => array('block__system', 'comment_wrapper__page', 'node__page'),
'default status' => 1,
'options' => array(
'custom' => array(
'class' => array('custom'),
),
),
);
return $skins;
}
function skinr_ui_test_skinr_skinr_ui_test_custom_form($form, $form_state, $context) {
$form = array(
'#type' => 'checkboxes',
'#title' => t('Custom'),
'#options' => array(
'custom' => t('Custom'),
),
);
return $form;
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* @file
* Default views.
*/
/**
* Implementation of hook_views_default_views().
*/
function skinr_ui_test_views_default_views() {
static $views;
if (isset($views)) {
return $views;
}
$files = file_scan_directory(drupal_get_path('module', 'skinr_ui_test') . '/views_default', '/\.inc$/');
foreach ($files as $filepath => $file) {
include $filepath;
if (isset($view)) {
$views[$view->name] = $view;
}
}
return $views;
}

View File

@@ -0,0 +1,69 @@
<?php
$view = new view;
$view->name = 'skinr_ui_test';
$view->description = 'Skinr UI Test view.';
$view->tag = 'default';
$view->base_table = 'node';
$view->human_name = 'Skinr UI Test';
$view->core = 7;
$view->api_version = '3.0-alpha1';
$view->disabled = FALSE;
/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Skinr UI Test';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['exposed_form']['type'] = 'basic';
$handler->display->display_options['pager']['type'] = 'full';
$handler->display->display_options['pager']['options']['items_per_page'] = '10';
$handler->display->display_options['style_plugin'] = 'default';
$handler->display->display_options['row_plugin'] = 'node';
/* Field: Content: Title */
$handler->display->display_options['fields']['title']['id'] = 'title';
$handler->display->display_options['fields']['title']['table'] = 'node';
$handler->display->display_options['fields']['title']['field'] = 'title';
$handler->display->display_options['fields']['title']['label'] = '';
$handler->display->display_options['fields']['title']['alter']['alter_text'] = 0;
$handler->display->display_options['fields']['title']['alter']['make_link'] = 0;
$handler->display->display_options['fields']['title']['alter']['absolute'] = 0;
$handler->display->display_options['fields']['title']['alter']['trim'] = 0;
$handler->display->display_options['fields']['title']['alter']['word_boundary'] = 0;
$handler->display->display_options['fields']['title']['alter']['ellipsis'] = 0;
$handler->display->display_options['fields']['title']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['title']['alter']['html'] = 0;
$handler->display->display_options['fields']['title']['hide_empty'] = 0;
$handler->display->display_options['fields']['title']['empty_zero'] = 0;
$handler->display->display_options['fields']['title']['link_to_node'] = 1;
/* Sort criterion: Content: Post date */
$handler->display->display_options['sorts']['created']['id'] = 'created';
$handler->display->display_options['sorts']['created']['table'] = 'node';
$handler->display->display_options['sorts']['created']['field'] = 'created';
$handler->display->display_options['sorts']['created']['order'] = 'DESC';
/* Filter criterion: Content: Published */
$handler->display->display_options['filters']['status']['id'] = 'status';
$handler->display->display_options['filters']['status']['table'] = 'node';
$handler->display->display_options['filters']['status']['field'] = 'status';
$handler->display->display_options['filters']['status']['value'] = 1;
$handler->display->display_options['filters']['status']['group'] = 0;
$handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
/* Display: Page */
$handler = $view->new_display('page', 'Page', 'page');
$handler->display->display_options['path'] = 'skinr-ui-test-view';
$translatables['skinr_ui_test'] = array(
t('Master'),
t('Skinr UI Test'),
t('more'),
t('Apply'),
t('Reset'),
t('Sort by'),
t('Asc'),
t('Desc'),
t('Items per page'),
t('- All -'),
t('Offset'),
t('Page'),
);