first import
339
sites/all/modules/quicktabs/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
78
sites/all/modules/quicktabs/README.txt
Normal file
@@ -0,0 +1,78 @@
|
||||
*******************************************************************************
|
||||
|
||||
Quicktabs
|
||||
|
||||
Description:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This module provides a form for admins to create a block of tabbed content by
|
||||
selecting a view, a node, a block or an existing Quicktabs instance as the content
|
||||
of each tab.
|
||||
The module can be extended to display other types of content.
|
||||
|
||||
|
||||
Installation & Use:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
1. Enable module in module list located at administer > structure > modules.
|
||||
2. Go to admin/structure/quicktabs and click on "Add Quicktabs Instance".
|
||||
3. Add a title (this will be the block title) and start entering information for your tabs
|
||||
4. Use the Add another tab button to add more tabs.
|
||||
5. Use the drag handles on the left to re-arrange tabs.
|
||||
6. Once you have defined all the tabs, click 'Save'.
|
||||
7. You new block will be available at admin/structure/blocks.
|
||||
8. Configure & enable it as required.
|
||||
9. To add tab styles to your Quicktabs instances, enable the quicktabs_tabstyles module
|
||||
10. Edit the default style at admin/structure/quicktabs/styles
|
||||
11. Control the style of individual Quicktabs instances by editing the instance in
|
||||
question and selecting from the style dropdown.
|
||||
|
||||
Note:
|
||||
-------------------------------------------------------------------------------
|
||||
Because Quicktabs allows your tabbed content to be pulled via ajax, it has its
|
||||
own menu callback for getting this content and returning it in JSON format. For
|
||||
node content, it uses the standard node_access check to make sure the user has
|
||||
access to this content. It is important to note that ANY node can be viewed
|
||||
from this menu callback; if you go to it directly at quicktabs/ajax/node/[nid]
|
||||
it will return a JSON text string of the node information. If there are certain
|
||||
fields in ANY of your nodes that are supposed to be private, these MUST be
|
||||
controlled at admin/content/node-type/MY_NODE_TYPE/display by setting them to
|
||||
be excluded on teaser and node view. Setting them as private through some other
|
||||
mechanism, e.g. Panels, will not affect their being displayed in an ajax Quicktab.
|
||||
|
||||
For Developers:
|
||||
-------------------------------------------------------------------------------
|
||||
The basic Quicktabs functionality can be extended in several ways. The most basic is
|
||||
to use the quicktabs_build_quicktabs() function to create Quicktabs instances
|
||||
programmatically, putting whatever you want into the Quicktabs instance. This function
|
||||
takes 3 parameters:
|
||||
$name - the name of an existing Quicktabs instance (i.e. existing in the database or
|
||||
in code), or a new name if creating an instance from scratch
|
||||
$overrides - an array of options to override the settings for the existing instance, or
|
||||
to override the default settings if creating an instance from scratch
|
||||
$custom_tabs - an array of tab content arrays. A very basic tab content array would be
|
||||
array('title' => 'My Custom Tab', 'contents' => 'Some text').
|
||||
One example of where this might prove useful is in a hook_page_alter implementation,
|
||||
where you could essentially put any render array that's part of the page into a
|
||||
Quicktabs instance. The contents property of a cusom tab can be a render array or
|
||||
a string of html.
|
||||
|
||||
Another way to extend Quicktabs is to add a renderer plugin. Quicktabs comes with
|
||||
3 renderer plugins: jQuery UI Tabs, jQuery UI Accordion, and classic Quicktabs. A
|
||||
renderer plugin is a class that extends the QuickRenderer class and implements the
|
||||
render() method, returning a render array that can be passed to drupal_render().
|
||||
See any of the existing renderer plugins for examples. Also see Quicktabs' implement-
|
||||
ation of hook_quicktabs_renderers().
|
||||
|
||||
Lastly, Quicktabs can be extended by adding new types of entities that can be loaded
|
||||
as tab content. Quicktabs itself provides the node, block, view, qtabs and callback
|
||||
tab content types. Your contents plugins should extend the QuickContent class. See
|
||||
the existing plugins and the hook_quicktabs_contents implementation for guidance.
|
||||
|
||||
|
||||
|
||||
Author:
|
||||
-------------------------------------------------------------------------------
|
||||
Katherine Bailey <katherine@katbailey.net>
|
||||
http://drupal.org/user/172987
|
||||
|
BIN
sites/all/modules/quicktabs/add-tab.gif
Normal file
After Width: | Height: | Size: 703 B |
79
sites/all/modules/quicktabs/css/quicktabs-admin.css
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
/* Admin form */
|
||||
|
||||
#qt-tablist-table .form-type-select label,
|
||||
#qt-tablist-table .form-type-textfield label {
|
||||
float: left;
|
||||
clear: left;
|
||||
min-width: 120px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
#qt-tablist-table .form-item {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
#qt-tablist-table .form-item .description {
|
||||
margin-top: 3px;
|
||||
}
|
||||
#qt-tablist-table .qt-tab-title {
|
||||
width: 130px;
|
||||
height: 125px;
|
||||
}
|
||||
#qt-tablist-table .qt-tab-type,
|
||||
#qt-tablist-table .qt-tab-remove {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#qt-tablist-table .description {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
#qt-tablist-table .qt-tab-title .form-item .form-text {
|
||||
width: 80px;
|
||||
}
|
||||
#qt-tablist-table .qt-tab-type label.option {
|
||||
width: auto;
|
||||
}
|
||||
#qt-tablist-table .qt-tab-content .form-item .form-text {
|
||||
width: 150px;
|
||||
}
|
||||
#qt-tablist-table .qt-tab-options-form {
|
||||
border-bottom: 1px solid #999;
|
||||
padding: 5px;
|
||||
}
|
||||
html.js #qt-tablist-table .qt-tab-options-form {
|
||||
display: none;
|
||||
border-bottom: none;
|
||||
padding: 0px;
|
||||
}
|
||||
#qt-tablist-table .qt-tab-remove label,
|
||||
#quicktabs-form #add-more-tabs-button label {
|
||||
font-weight: bold;
|
||||
float: left;
|
||||
clear: left;
|
||||
width: auto;
|
||||
}
|
||||
#quicktabs-form #add-more-tabs-button {
|
||||
width: 100px;
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
float: right;
|
||||
}
|
||||
#quicktabs-form .add-tab,
|
||||
#qt-tablist-table .delete-tab {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
width: 39px;
|
||||
height: 23px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
text-indent: -9999px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#quicktabs-form .add-tab {
|
||||
background: transparent url(../add-tab.gif) no-repeat 0 -3px;
|
||||
}
|
||||
#quicktabs-form .delete-tab {
|
||||
background: transparent url(../delete-tab.gif) no-repeat 0 0;
|
||||
}
|
17
sites/all/modules/quicktabs/css/quicktabs.css
Normal file
@@ -0,0 +1,17 @@
|
||||
.quicktabs-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs {
|
||||
margin-top: 0;
|
||||
}
|
||||
ul.quicktabs-tabs li {
|
||||
display: inline;
|
||||
background: none;
|
||||
list-style-type: none;
|
||||
padding: 2px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
ul.quicktabs-tabs li a:focus {
|
||||
outline: none;
|
||||
}
|
BIN
sites/all/modules/quicktabs/delete-tab.gif
Normal file
After Width: | Height: | Size: 1.3 KiB |
166
sites/all/modules/quicktabs/includes/quicktabs_style_plugin.inc
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
// Id:$
|
||||
|
||||
/**
|
||||
* @file Add Quicktabs style plugins to Views.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Style plugin to display Quicktabs.
|
||||
*/
|
||||
class quicktabs_style_plugin extends views_plugin_style {
|
||||
|
||||
// Allow some options for the style.
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
$options['tab_style'] = array('default' => 'default');
|
||||
$options['tab_title_field'] = array('default' => NULL);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
// Create the options form.
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
$options = array();
|
||||
$styles = module_invoke_all('quicktabs_tabstyles');
|
||||
// The keys used for options must be valid html id-s.
|
||||
// Removing the css file path, because that can't be used.
|
||||
foreach ($styles as $style) {
|
||||
$options[$style] = $style;
|
||||
}
|
||||
ksort($options);
|
||||
$form['tab_style'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Tab style'),
|
||||
'#options' => array('nostyle' => t('No style'), 'default' => t('Default style')) + $options,
|
||||
'#default_value' => $this->options['tab_style'],
|
||||
'#description' => t('The tab style that will be applied to this set of tabs. Note that this style may not show in the live preview.'),
|
||||
'#weight' => -5,
|
||||
);
|
||||
|
||||
if (isset($form['grouping'])) {
|
||||
$options = array();
|
||||
foreach (element_children($form['grouping']) as $key => $value) {
|
||||
if (!empty($form['grouping'][$key]['field']['#options']) && is_array($form['grouping'][$key]['field']['#options'])) {
|
||||
$options = array_merge($options, $form['grouping'][$key]['field']['#options']);
|
||||
}
|
||||
}
|
||||
|
||||
unset($options['']);
|
||||
$form['tab_title_field'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Title field'),
|
||||
'#options' => $options,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $this->options['tab_title_field'],
|
||||
'#description' => t('Select the field that will be used as the tab title.'),
|
||||
'#weight' => -3,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we have all the settings necessary to render into tabs.
|
||||
function validate() {
|
||||
$errors = parent::validate();
|
||||
|
||||
// Ensure that we're using the field row style.
|
||||
if (!$this->row_plugin->uses_fields()) {
|
||||
$errors[] = t('Display "@display" uses the "@style" row style, but the Quicktabs display style requires use of the "Fields" row style.', array('@display' => $this->display->display_title, '@style' => $this->row_plugin->definition['title']));
|
||||
}
|
||||
|
||||
// Ensure that a valid tab title field is selected.
|
||||
$fields = $this->display->handler->get_handlers('field');
|
||||
if (empty($this->options['tab_title_field']) || !isset($fields[$this->options['tab_title_field']])) {
|
||||
$errors[] = t('The Quicktabs display style requires that a field be configured to be used as the tab title.');
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
// Override the render functionality.
|
||||
function render() {
|
||||
if (empty($this->row_plugin)) {
|
||||
vpr('views_plugin_style_default: Missing row plugin');
|
||||
return;
|
||||
}
|
||||
|
||||
$view = $this->view;
|
||||
$qt_name = 'view__' . $view->name .'__'. $view->current_display;
|
||||
|
||||
// Group the rows according to the grouping field, if specified.
|
||||
$sets = $this->render_grouping($this->view->result, $this->options['grouping']);
|
||||
$tabs = array();
|
||||
|
||||
foreach ($sets as $title => $records) {
|
||||
if ($this->uses_row_plugin()) {
|
||||
$rows = array();
|
||||
foreach ($records as $row_index => $row) {
|
||||
$this->view->row_index = $row_index;
|
||||
$rows[] = $this->row_plugin->render($row);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$rows = $records;
|
||||
}
|
||||
|
||||
// If grouped, we'll be using the group title for each tab.
|
||||
if ($this->options['grouping']) {
|
||||
|
||||
// Remove labels from titles.
|
||||
foreach (element_children($this->options['grouping']) as $key => $value) {
|
||||
if (!empty($this->view->field[$this->options['grouping'][$key]['field']]->options['label'])) {
|
||||
$title = str_replace($this->view->field[$this->options['grouping'][$key]['field']]->options['label'] . ': ', '', $title);
|
||||
}
|
||||
}
|
||||
|
||||
$contents = '';
|
||||
foreach ($rows as $row) {
|
||||
$contents .= '<div class="quicktabs-views-group">' . $row . '</div>';
|
||||
}
|
||||
$tabs[] = array(
|
||||
'title' => $title,
|
||||
'contents' => array('#markup' => $contents),
|
||||
);
|
||||
}
|
||||
|
||||
// If not grouped, there's just one set of rows that we loop through.
|
||||
else {
|
||||
foreach ($rows as $index => $row) {
|
||||
$title = $this->get_field($index, $this->options['tab_title_field']);
|
||||
$tabs[] = array(
|
||||
'title' => $title,
|
||||
'contents' => array('#markup' => $row),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$overrides = array('style' => $view->style_options['tab_style'], 'sorted' => TRUE);
|
||||
$quicktabs = quicktabs_build_quicktabs($qt_name, $overrides, $tabs);
|
||||
|
||||
$output = drupal_render($quicktabs);
|
||||
|
||||
// If doing a live preview, add the JavaScript directly to the output.
|
||||
if (isset($view->live_preview) && $view->live_preview) {
|
||||
$js = drupal_add_js();
|
||||
$qtsettings = array();
|
||||
foreach ($js['settings']['data'] as $settings) {
|
||||
if (isset($settings['quicktabs']['qt_'. $qt_name])) {
|
||||
$qtsettings = $settings['quicktabs']['qt_'. $qt_name];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$output .= "<script type=\"text/javascript\">\n";
|
||||
$output .= "Drupal.settings.quicktabs = Drupal.settings.quicktabs || {};\n";
|
||||
$output .= "jQuery.extend(Drupal.settings.quicktabs, ". json_encode(array('qt_'. $qt_name => $qtsettings)) .");\n";
|
||||
$output .= "</script>\n";
|
||||
}
|
||||
|
||||
unset($view->row_index);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
23
sites/all/modules/quicktabs/js/qt_accordion.js
Normal file
@@ -0,0 +1,23 @@
|
||||
(function ($) {
|
||||
|
||||
Drupal.behaviors.qt_accordion = {
|
||||
attach: function (context, settings) {
|
||||
$('.quick-accordion', context).once(function(){
|
||||
var id = $(this).attr('id');
|
||||
var qtKey = 'qt_' + this.id.substring(this.id.indexOf('-') +1);
|
||||
var options = settings.quicktabs[qtKey].options;
|
||||
|
||||
options.active = parseInt(settings.quicktabs[qtKey].active_tab);
|
||||
if (settings.quicktabs[qtKey].history) {
|
||||
options.event = 'change';
|
||||
$(this).accordion(options);
|
||||
Drupal.quicktabsBbq($(this), 'h3 a', 'h3');
|
||||
}
|
||||
else {
|
||||
$(this).accordion(options);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery);
|
21
sites/all/modules/quicktabs/js/qt_ui_tabs.js
Normal file
@@ -0,0 +1,21 @@
|
||||
(function ($) {
|
||||
|
||||
Drupal.behaviors.qt_ui_tabs = {
|
||||
attach: function (context, settings) {
|
||||
|
||||
$('.quicktabs-ui-wrapper').once('qt-ui-tabs-processed', function() {
|
||||
var id = $(this).attr('id');
|
||||
var qtKey = 'qt_' + id.substring(id.indexOf('-') +1);
|
||||
if (!settings.quicktabs[qtKey].history) {
|
||||
$(this).tabs();
|
||||
}
|
||||
else {
|
||||
$(this).tabs({event: 'change'});
|
||||
Drupal.quicktabsBbq($(this), 'ul.ui-tabs-nav a');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery);
|
119
sites/all/modules/quicktabs/js/quicktabs.js
Normal file
@@ -0,0 +1,119 @@
|
||||
(function ($) {
|
||||
Drupal.settings.views = Drupal.settings.views || {'ajax_path': '/views/ajax'};
|
||||
|
||||
Drupal.quicktabs = Drupal.quicktabs || {};
|
||||
|
||||
Drupal.quicktabs.getQTName = function (el) {
|
||||
return el.id.substring(el.id.indexOf('-') +1);
|
||||
}
|
||||
|
||||
Drupal.behaviors.quicktabs = {
|
||||
attach: function (context, settings) {
|
||||
$.extend(true, Drupal.settings, settings);
|
||||
$('.quicktabs-wrapper', context).once(function(){
|
||||
Drupal.quicktabs.prepare(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Setting up the inital behaviours
|
||||
Drupal.quicktabs.prepare = function(el) {
|
||||
// el.id format: "quicktabs-$name"
|
||||
var qt_name = Drupal.quicktabs.getQTName(el);
|
||||
var $ul = $(el).find('ul.quicktabs-tabs:first');
|
||||
$ul.find('li a').each(function(i, element){
|
||||
element.myTabIndex = i;
|
||||
element.qt_name = qt_name;
|
||||
var tab = new Drupal.quicktabs.tab(element);
|
||||
var parent_li = $(element).parents('li').get(0);
|
||||
if ($(parent_li).hasClass('active')) {
|
||||
$(element).addClass('quicktabs-loaded');
|
||||
}
|
||||
$(element).once(function() {$(this).bind('click', {tab: tab}, Drupal.quicktabs.clickHandler);});
|
||||
});
|
||||
}
|
||||
|
||||
Drupal.quicktabs.clickHandler = function(event) {
|
||||
var tab = event.data.tab;
|
||||
var element = this;
|
||||
// Set clicked tab to active.
|
||||
$(this).parents('li').siblings().removeClass('active');
|
||||
$(this).parents('li').addClass('active');
|
||||
|
||||
// Hide all tabpages.
|
||||
tab.container.children().addClass('quicktabs-hide');
|
||||
|
||||
if (!tab.tabpage.hasClass("quicktabs-tabpage")) {
|
||||
tab = new Drupal.quicktabs.tab(element);
|
||||
}
|
||||
|
||||
tab.tabpage.removeClass('quicktabs-hide');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Constructor for an individual tab
|
||||
Drupal.quicktabs.tab = function (el) {
|
||||
this.element = el;
|
||||
this.tabIndex = el.myTabIndex;
|
||||
var qtKey = 'qt_' + el.qt_name;
|
||||
var i = 0;
|
||||
for (var key in Drupal.settings.quicktabs[qtKey].tabs) {
|
||||
if (i == this.tabIndex) {
|
||||
this.tabObj = Drupal.settings.quicktabs[qtKey].tabs[key];
|
||||
this.tabKey = key;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
this.tabpage_id = 'quicktabs-tabpage-' + el.qt_name + '-' + this.tabKey;
|
||||
this.container = $('#quicktabs-container-' + el.qt_name);
|
||||
this.tabpage = this.container.find('#' + this.tabpage_id);
|
||||
}
|
||||
|
||||
if (Drupal.ajax) {
|
||||
/**
|
||||
* Handle an event that triggers an AJAX response.
|
||||
*
|
||||
* We unfortunately need to override this function, which originally comes from
|
||||
* misc/ajax.js, in order to be able to cache loaded tabs, i.e. once a tab
|
||||
* content has loaded it should not need to be loaded again.
|
||||
*
|
||||
* I have removed all comments that were in the original core function, so that
|
||||
* the only comments inside this function relate to the Quicktabs modification
|
||||
* of it.
|
||||
*/
|
||||
Drupal.ajax.prototype.eventResponse = function (element, event) {
|
||||
var ajax = this;
|
||||
|
||||
if (ajax.ajaxing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (ajax.form) {
|
||||
if (ajax.setClick) {
|
||||
element.form.clk = element;
|
||||
}
|
||||
|
||||
ajax.form.ajaxSubmit(ajax.options);
|
||||
}
|
||||
else {
|
||||
// Do not perform an ajax request for already loaded Quicktabs content.
|
||||
if (!$(element).hasClass('quicktabs-loaded')) {
|
||||
ajax.beforeSerialize(ajax.element, ajax.options);
|
||||
$.ajax(ajax.options);
|
||||
if ($(element).parents('ul').hasClass('quicktabs-tabs')) {
|
||||
$(element).addClass('quicktabs-loaded');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
ajax.ajaxing = false;
|
||||
alert("An error occurred while attempting to process " + ajax.options.url + ": " + e.message);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
})(jQuery);
|
37
sites/all/modules/quicktabs/js/quicktabs_bbq.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @file
|
||||
* Implements history using the BBQ plugin.
|
||||
* See http://benalman.com/code/projects/jquery-bbq/examples/fragment-jquery-ui-tabs
|
||||
*/
|
||||
(function($) {
|
||||
|
||||
Drupal.quicktabsBbq = function($tabset, clickSelector, changeSelector) {
|
||||
|
||||
changeSelector = changeSelector || clickSelector;
|
||||
|
||||
// Define our own click handler for the tabs, overriding the default.
|
||||
$(clickSelector, $tabset).each(function(i, el){
|
||||
this.tabIndex = i;
|
||||
$(this).click(function(e){
|
||||
e.preventDefault();
|
||||
var state = {},
|
||||
id = $tabset.attr('id'), // qt container id
|
||||
idx = this.tabIndex; // tab index
|
||||
|
||||
state[id] = idx;
|
||||
$.bbq.pushState(state);
|
||||
});
|
||||
});
|
||||
|
||||
$(window).bind('hashchange', function(e) {
|
||||
$tabset.each(function() {
|
||||
var idx = $.bbq.getState(this.id, true);
|
||||
var $active_link = $(this).find(changeSelector).eq(idx);
|
||||
$active_link.triggerHandler('change');
|
||||
});
|
||||
});
|
||||
|
||||
$(window).trigger('hashchange');
|
||||
}
|
||||
|
||||
})(jQuery);
|
17
sites/all/modules/quicktabs/js/quicktabs_form.js
Normal file
@@ -0,0 +1,17 @@
|
||||
(function ($) {
|
||||
|
||||
Drupal.quicktabsShowHide = function() {
|
||||
$(this).parents('tr').find('div.qt-tab-' + this.value + '-options-form').show().siblings('div.qt-tab-options-form').hide();
|
||||
};
|
||||
|
||||
Drupal.behaviors.quicktabsform = {
|
||||
attach: function (context, settings) {
|
||||
$('#quicktabs-form tr').once(function(){
|
||||
var currentRow = $(this);
|
||||
currentRow.find('div.form-item :input[name*="type"]').bind('click', Drupal.quicktabsShowHide);
|
||||
$(':input[name*="type"]:checked', this).trigger('click');
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
98
sites/all/modules/quicktabs/plugins/QuickAccordion.inc
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Renders the content using the jQuery UI Accordion widget.
|
||||
*/
|
||||
class QuickAccordion extends QuickRenderer {
|
||||
|
||||
public static function optionsForm($qt) {
|
||||
$form = array();
|
||||
$form['history'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => 'History',
|
||||
'#description' => t('Store tab state in the URL allowing for browser back / forward and bookmarks.'),
|
||||
'#default_value' => (isset($qt->renderer) && $qt->renderer == 'accordion' && isset($qt->options['history']) && $qt->options['history']),
|
||||
);
|
||||
$form['jquery_ui'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('JQuery UI options'),
|
||||
);
|
||||
$form['jquery_ui']['autoHeight'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => 'Autoheight',
|
||||
'#default_value' => (isset($qt->renderer) && $qt->renderer == 'accordion' && isset($qt->options['jquery_ui']['autoHeight']) && $qt->options['jquery_ui']['autoHeight']),
|
||||
);
|
||||
$form['jquery_ui']['collapsible'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Collapsible'),
|
||||
'#default_value' => (isset($qt->renderer) && $qt->renderer == 'accordion' && isset($qt->options['jquery_ui']['collapsible']) && $qt->options['jquery_ui']['collapsible']),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$quickset = $this->quickset;
|
||||
$qsid = 'quickset-' . $quickset->getName();
|
||||
// Build our render array...
|
||||
$render_array = array();
|
||||
$render_array['#attached'] = $this->add_attached();
|
||||
$render_array['content'] = array(
|
||||
'#theme' => 'qt_accordion',
|
||||
'#options' => array('attributes' => array(
|
||||
'id' => $qsid,
|
||||
'class' => array('quick-accordion'),
|
||||
)),
|
||||
'divs' => array(),
|
||||
);
|
||||
|
||||
// Render all tab content.
|
||||
foreach ($quickset->getContents() as $key => $item) {
|
||||
if (!empty($item)) {
|
||||
$render_array['content']['divs'][] = array(
|
||||
'#prefix' => '<h3><a href= "#'. $qsid . '_' . $key .'">'. check_plain($quickset->translateString($item->getTitle(), 'tab', $key)) .'</a></h3><div>',
|
||||
'#suffix' => '</div>',
|
||||
'content' => $item->render(),
|
||||
);
|
||||
}
|
||||
}
|
||||
return $render_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any necessary js, css and libraries for the render array.
|
||||
*/
|
||||
protected function add_attached() {
|
||||
$settings = $this->quickset->getSettings();
|
||||
$options = $settings['options'];
|
||||
|
||||
$attached = array(
|
||||
'library' => array(
|
||||
array('system', 'ui.accordion'),
|
||||
),
|
||||
'js' => array(
|
||||
array('data' => drupal_get_path('module', 'quicktabs') . '/js/qt_accordion.js'),
|
||||
),
|
||||
);
|
||||
|
||||
$javascript = drupal_add_js();
|
||||
foreach ($javascript['settings']['data'] as $key => $settings) {
|
||||
if (key($settings) == 'quicktabs') {
|
||||
$qtkey = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['history']) {
|
||||
$attached['library'][] = array('system', 'jquery.bbq');
|
||||
$attached['js'][] = array('data' => drupal_get_path('module', 'quicktabs') . '/js/quicktabs_bbq.js');
|
||||
}
|
||||
|
||||
$name = $this->quickset->getName();
|
||||
if (!isset($qtkey) || !array_key_exists('qt_' . $name, $javascript['settings']['data'][$qtkey]['quicktabs'])) {
|
||||
$quicktabs_array = array('name' => $name, 'active_tab' => $this->quickset->getActiveTab(), 'options' => $options['jquery_ui'], 'history' => $options['history']);
|
||||
$attached['js'][] = array('data' => array('quicktabs' => array('qt_'. $name => $quicktabs_array)), 'type' => 'setting');
|
||||
}
|
||||
return $attached;
|
||||
}
|
||||
|
||||
}
|
93
sites/all/modules/quicktabs/plugins/QuickBlockContent.inc
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for tab content of type "block" - this is for rendering a block as tab
|
||||
* content.
|
||||
*/
|
||||
class QuickBlockContent extends QuickContent {
|
||||
|
||||
public static function getType() {
|
||||
return 'block';
|
||||
}
|
||||
|
||||
public function optionsForm($delta, $qt) {
|
||||
$tab = $this->settings;
|
||||
$form = array();
|
||||
$form['block']['bid'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => quicktabs_get_blocks(),
|
||||
'#default_value' => isset($tab['bid']) ? $tab['bid'] : '',
|
||||
'#title' => t('Select a block'),
|
||||
);
|
||||
$form['block']['hide_title'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Hide the title of this block'),
|
||||
'#default_value' => isset($tab['hide_title']) ? $tab['hide_title'] : 1,
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function render($hide_empty = FALSE, $args = array()) {
|
||||
if ($this->rendered_content) {
|
||||
return $this->rendered_content;
|
||||
}
|
||||
$output = array();
|
||||
$item = $this->settings;
|
||||
if (!empty($args)) {
|
||||
// The args have been passed in from an ajax request.
|
||||
$qt_name = array_shift($args);
|
||||
list($item['bid'], $item['hide_title']) = $args;
|
||||
|
||||
// Ensure the block is assigned to the requested quicktabs block. This test prevents
|
||||
// AJAX access to blocks that have not been added to an AJAX-enabled quicktabs block.
|
||||
$break = TRUE;
|
||||
$quicktabs = quicktabs_load($qt_name);
|
||||
// Ensure AJAX is enabled for the quicktabs block.
|
||||
if (!empty($quicktabs) && $quicktabs->ajax == 1) {
|
||||
// Ensure the requested tab has been added to the quicktabs block.
|
||||
foreach ($quicktabs->tabs as $quicktab) {
|
||||
if (isset($quicktab['bid']) && ($quicktab['bid'] == $item['bid'])) {
|
||||
$break = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($break == TRUE) {
|
||||
if (!$hide_empty) {
|
||||
$output['#markup'] = theme('quicktabs_tab_access_denied', $item);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($item['bid'])) {
|
||||
if (module_exists('block')) {
|
||||
$pos = strpos($item['bid'], '_delta_');
|
||||
$module = drupal_substr($item['bid'], 0, $pos);
|
||||
$delta = drupal_substr($item['bid'], $pos + 7);
|
||||
|
||||
$block = block_load($module, $delta);
|
||||
$block->region = 'quicktabs_tabpage';
|
||||
|
||||
if ($block_arr = _block_render_blocks(array($block))) {
|
||||
if ($item['hide_title']) {
|
||||
$block_arr["{$block->module}_{$block->delta}"]->subject = FALSE;
|
||||
}
|
||||
if (!empty($block_arr["{$block->module}_{$block->delta}"]->content)) {
|
||||
$build = _block_get_renderable_array($block_arr);
|
||||
$output = $build;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!$hide_empty) {
|
||||
$output['#markup'] = t('Block module is not enabled, cannot display content.');
|
||||
}
|
||||
}
|
||||
$this->rendered_content = $output;
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function getAjaxKeys() {
|
||||
return array('bid', 'hide_title');
|
||||
}
|
||||
}
|
92
sites/all/modules/quicktabs/plugins/QuickCallbackContent.inc
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for tab content of type "callback" - this is for rendering the contents
|
||||
* of some menu callback function as tab content.
|
||||
*/
|
||||
class QuickCallbackContent extends QuickContent {
|
||||
|
||||
public static function getType() {
|
||||
return 'callback';
|
||||
}
|
||||
|
||||
public function __construct($item) {
|
||||
parent::__construct($item);
|
||||
|
||||
if (isset($item['path'])) {
|
||||
$url_args = arg();
|
||||
$path = $item['path'];
|
||||
|
||||
foreach ($url_args as $id => $arg) {
|
||||
$path = str_replace("%$id", $arg, $path);
|
||||
}
|
||||
$path = preg_replace(',/?(%\d),', '', $path);
|
||||
if (!empty($path)) {
|
||||
$this->settings['ajax_path'] = rawurlencode($path);
|
||||
}
|
||||
else {
|
||||
$this->settings['ajax_path'] = '';
|
||||
}
|
||||
$this->settings['actual_path'] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
public function optionsForm($delta, $qt) {
|
||||
$tab = $this->settings;
|
||||
$form = array();
|
||||
$form['callback']['path'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => isset($tab['path']) ? $tab['path'] : '',
|
||||
'#title' => t('Path'),
|
||||
'#element_validate' => array('quicktabs_callback_element_validate'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function render($hide_empty = FALSE, $args = array()) {
|
||||
if ($this->rendered_content) {
|
||||
return $this->rendered_content;
|
||||
}
|
||||
$item = $this->settings;
|
||||
if (!empty($args)) {
|
||||
// The args have been passed in from an ajax request.
|
||||
// The first element of the args array is the qt_name, which we don't need
|
||||
// for this content type.
|
||||
array_shift($args);
|
||||
$item['actual_path'] = rawurldecode($args[0]);
|
||||
$_GET['q'] = $item['actual_path'];
|
||||
}
|
||||
|
||||
$output = array();
|
||||
if (isset($item['actual_path'])) {
|
||||
// Retain the current page title as we'll need to set it back after
|
||||
// calling menu_execute_active_handler().
|
||||
$page_title = drupal_get_title();
|
||||
$response = menu_execute_active_handler($item['actual_path'], FALSE);
|
||||
// Revert the page title.
|
||||
drupal_set_title($page_title);
|
||||
|
||||
if (!is_array($response)) {
|
||||
if (is_int($response)) {
|
||||
if (MENU_ACCESS_DENIED == $response && !$hide_empty) {
|
||||
$output['#markup'] = theme('quicktabs_tab_access_denied', array('tab' => $item));
|
||||
}
|
||||
// For any other integer response form the menu callback, we'll just
|
||||
// return an empty array.
|
||||
}
|
||||
else {
|
||||
$output = array('#markup' => $response);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$output = $response;
|
||||
}
|
||||
}
|
||||
$this->rendered_content = $output;
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function getAjaxKeys() {
|
||||
return array('ajax_path');
|
||||
}
|
||||
}
|
72
sites/all/modules/quicktabs/plugins/QuickNodeContent.inc
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for tab content of type "node" - this is for rendering a node as tab
|
||||
* content.
|
||||
*/
|
||||
class QuickNodeContent extends QuickContent {
|
||||
|
||||
public static function getType() {
|
||||
return 'node';
|
||||
}
|
||||
|
||||
public function optionsForm($delta, $qt) {
|
||||
$tab = $this->settings;
|
||||
$form = array();
|
||||
$form['node']['nid'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Node'),
|
||||
'#description' => t('The node ID of the node.'),
|
||||
'#maxlength' => 10,
|
||||
'#size' => 20,
|
||||
'#default_value' => isset($tab['nid']) ? $tab['nid'] : '',
|
||||
);
|
||||
$form['node']['teaser'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Teaser view'),
|
||||
'#default_value' => isset($tab['teaser']) ? $tab['teaser'] : 0,
|
||||
);
|
||||
$form['node']['hide_title'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Hide the title of this node'),
|
||||
'#default_value' => isset($tab['hide_title']) ? $tab['hide_title'] : 1,
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function render($hide_empty = FALSE, $args = array()) {
|
||||
if ($this->rendered_content) {
|
||||
return $this->rendered_content;
|
||||
}
|
||||
$item = $this->settings;
|
||||
if (!empty($args)) {
|
||||
// The args have been passed in from an ajax request.
|
||||
// The first element of the args array is the qt_name, which we don't need
|
||||
// for this content type.
|
||||
array_shift($args);
|
||||
list($item['nid'], $item['teaser'], $item['hide_title']) = $args;
|
||||
}
|
||||
$output = array();
|
||||
if (isset($item['nid'])) {
|
||||
$node = node_load($item['nid']);
|
||||
if (!empty($node)) {
|
||||
if (node_access('view', $node)) {
|
||||
$buildmode = $item['teaser'] ? 'teaser' : 'full';
|
||||
$nstruct = node_view($node, $buildmode);
|
||||
if ($item['hide_title']) {
|
||||
$nstruct['#node']->title = NULL;
|
||||
}
|
||||
$output = $nstruct;
|
||||
}
|
||||
elseif (!$hide_empty) {
|
||||
$output = array('#markup' => theme('quicktabs_tab_access_denied', array('tab' => $item)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function getAjaxKeys() {
|
||||
return array('nid', 'teaser', 'hide_title');
|
||||
}
|
||||
}
|
65
sites/all/modules/quicktabs/plugins/QuickQtabsContent.inc
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for tab content of type "qtabs" - this is for rendering a QuickSet instance
|
||||
* as the tab content of another QuickSet instance.
|
||||
*/
|
||||
class QuickQtabsContent extends QuickContent {
|
||||
|
||||
public static function getType() {
|
||||
return 'qtabs';
|
||||
}
|
||||
|
||||
public function optionsForm($delta, $qt) {
|
||||
$tab = $this->settings;
|
||||
$form = array();
|
||||
$tab_options = array();
|
||||
foreach (quicktabs_load_multiple() as $machine_name => $info) {
|
||||
// Do not offer the option to put a tab inside itself.
|
||||
if (!isset($qt->machine_name) || $machine_name != $qt->machine_name) {
|
||||
$tab_options[$machine_name] = $info->title;
|
||||
}
|
||||
}
|
||||
$form['qtabs']['machine_name'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Quicktabs instance'),
|
||||
'#description' => t('The Quicktabs instance to put inside this tab.'),
|
||||
'#options' => $tab_options,
|
||||
'#default_value' => isset($tab['machine_name']) ? $tab['machine_name'] : '',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function render($hide_empty = FALSE, $args = array()) {
|
||||
if ($this->rendered_content) {
|
||||
return $this->rendered_content;
|
||||
}
|
||||
$item = $this->settings;
|
||||
if (!empty($args)) {
|
||||
// The args have been passed in from an ajax request.
|
||||
// The first element of the args array is the qt_name, which we don't need
|
||||
// for this content type.
|
||||
array_shift($args);
|
||||
$item['machine_name'] = $args[0];
|
||||
}
|
||||
|
||||
$output = array();
|
||||
if (isset($item['machine_name'])) {
|
||||
if ($quicktabs = quicktabs_load($item['machine_name'])) {
|
||||
$contents = $quicktabs->tabs;
|
||||
$name = $quicktabs->machine_name;
|
||||
unset($quicktabs->tabs, $quicktabs->machine_name);
|
||||
$options = (array) $quicktabs;
|
||||
if ($qt = QuickSet::QuickSetRendererFactory($name, $contents, $quicktabs->renderer, $options)) {
|
||||
$output = $qt->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->rendered_content = $output;
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function getAjaxKeys() {
|
||||
return array('machine_name');
|
||||
}
|
||||
}
|
156
sites/all/modules/quicktabs/plugins/QuickQuicktabs.inc
Normal file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Renders the content using the original Quicktabs mechanism of previous versions.
|
||||
* Includes support for ajax rendered content.
|
||||
*/
|
||||
class QuickQuicktabs extends QuickRenderer {
|
||||
|
||||
public function render() {
|
||||
$quickset = $this->quickset;
|
||||
|
||||
$render_array = array();
|
||||
|
||||
$active_tab = $quickset->getActiveTab();
|
||||
if ($tabs = $this->build_tablinks($active_tab)) {
|
||||
$render_array['#attached'] = $this->add_attached();
|
||||
|
||||
$qt_name = $quickset->getName();
|
||||
$settings = $quickset->getSettings();
|
||||
$contents = $quickset->getContents();
|
||||
|
||||
$render_array['content'] = array(
|
||||
'#theme' => 'qt_quicktabs',
|
||||
'#options' => array('attributes' => array(
|
||||
'id' => 'quicktabs-' . $qt_name,
|
||||
'class' => 'quicktabs-wrapper quicktabs-style-' . drupal_strtolower($settings['style']),
|
||||
)),
|
||||
'tabs' => array('#theme' => 'qt_quicktabs_tabset', '#options' => array('active' => $active_tab, 'style' => drupal_strtolower($settings['style'])), 'tablinks' => $tabs),
|
||||
// The main content area, each quicktab container needs a unique id.
|
||||
'container' => array(
|
||||
'#prefix' => '<div id="quicktabs-container-' . $qt_name .'" class="quicktabs_main quicktabs-style-' . drupal_strtolower($settings['style']) .'">',
|
||||
'#suffix' => '</div>',
|
||||
'divs' => array(),
|
||||
),
|
||||
);
|
||||
|
||||
// If in ajax mode, we'll only be rendering one tab, otherwise all of them.
|
||||
$tabs_to_render = $settings['ajax'] ? array($active_tab => $contents[$active_tab]) : $contents;
|
||||
foreach ($tabs_to_render as $key => $tab) {
|
||||
if (!empty($tab)) {
|
||||
$attribs = array(
|
||||
'id' => 'quicktabs-tabpage-'. $qt_name . '-'. $key,
|
||||
'class' => array('quicktabs-tabpage', ($active_tab == $key ? '' : 'quicktabs-hide')),
|
||||
);
|
||||
$render_array['content']['container']['divs'][] = array(
|
||||
'#prefix' => '<div '. drupal_attributes($attribs) .'>',
|
||||
'#suffix' => '</div>',
|
||||
'content' => $tab->render(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $render_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the actual tab links, with appropriate href, title and attributes.
|
||||
*
|
||||
* @param $active_tab The index of the active tab.
|
||||
*/
|
||||
protected function build_tablinks($active_tab) {
|
||||
$quickset = $this->quickset;
|
||||
$settings = $quickset->getSettings();
|
||||
$tabs = array();
|
||||
foreach ($quickset->getContents() as $i => $tab) {
|
||||
if (!empty($tab)) {
|
||||
$tablink = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $quickset->translateString($tab->getTitle(), 'tab', $i),
|
||||
'#href' => $_GET['q'],
|
||||
'#options' => $this->construct_link_options($i),
|
||||
);
|
||||
if ($settings['ajax']) {
|
||||
$tab_settings = $tab->getSettings();
|
||||
$ajax_keys = $tab->getAjaxKeys();
|
||||
$ajax_args = array();
|
||||
foreach ($ajax_keys as $key) {
|
||||
$ajax_args[] = $tab_settings[$key];
|
||||
}
|
||||
$ajax_path = $quickset->getAjaxPath($i, $tab->getType());
|
||||
$ajax_href = $ajax_path . '/'. implode('/', $ajax_args);
|
||||
$tablink['#ajax'] = array(
|
||||
'progress' => array('message' => '', 'type' => 'throbber'),
|
||||
'path' => $ajax_href,
|
||||
);
|
||||
}
|
||||
$tabs[$i] = $tablink;
|
||||
}
|
||||
}
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any necessary js, css and libraries for the render array.
|
||||
*/
|
||||
protected function add_attached() {
|
||||
$attached = array(
|
||||
'css' => array(
|
||||
array('data' => drupal_get_path('module', 'quicktabs') .'/css/quicktabs.css'),
|
||||
),
|
||||
'js' => array(
|
||||
array('data' => drupal_get_path('module', 'quicktabs') . '/js/quicktabs.js'),
|
||||
array('data' => 'misc/progress.js', 'weight' => JS_LIBRARY),
|
||||
),
|
||||
);
|
||||
$settings = $this->quickset->getSettings();
|
||||
// Add the custom style css if a custom style has been set.
|
||||
$style_css = quicktabs_get_css($settings['style']);
|
||||
if (!empty($style_css)) {
|
||||
$attached['css'][] = $style_css;
|
||||
}
|
||||
// Prepare a tab_settings array for passing the tab info to our JavaScript.
|
||||
$tab_settings = array();
|
||||
foreach ($this->quickset->getContents() as $i => $content) {
|
||||
if (!empty($content)) {
|
||||
$tab_settings[$i] = $content->getSettings();
|
||||
}
|
||||
}
|
||||
// Add our JS settings
|
||||
$javascript = drupal_add_js();
|
||||
foreach ($javascript['settings']['data'] as $key => $settings) {
|
||||
if (key($settings) == 'quicktabs') {
|
||||
$qtkey = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$name = $this->quickset->getName();
|
||||
if (!isset($qtkey) || (isset($javascript['settings']['data'][$qtkey]['quicktabs'])
|
||||
&& !array_key_exists('qt_' . $name, $javascript['settings']['data'][$qtkey]['quicktabs']))) {
|
||||
$quicktabs_array = array_merge(array('name' => $name, 'tabs' => $tab_settings), $settings);
|
||||
$attached['js'][] = array('data' => array('quicktabs' => array('qt_' . $name => $quicktabs_array)), 'type' => 'setting');
|
||||
}
|
||||
return $attached;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to construct link options for tab links.
|
||||
*/
|
||||
protected function construct_link_options($tabkey) {
|
||||
$qt_name = $this->quickset->getName();
|
||||
$id = 'quicktabs-tab-' . implode('-', array($qt_name, $tabkey));
|
||||
|
||||
// Need to construct the correct querystring for the tab links.
|
||||
$query = drupal_get_query_parameters(NULL, array("qt-$qt_name", 'q', 'page'));
|
||||
$query["qt-{$qt_name}"] = $tabkey;
|
||||
|
||||
$link_options = array(
|
||||
'attributes' => array(
|
||||
'id' => $id,
|
||||
),
|
||||
'query' => $query,
|
||||
'fragment' => 'qt-' . $qt_name,
|
||||
);
|
||||
return $link_options;
|
||||
}
|
||||
}
|
113
sites/all/modules/quicktabs/plugins/QuickUiTabs.inc
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Renders the content using the jQuery UI Tabs widget.
|
||||
*/
|
||||
class QuickUiTabs extends QuickRenderer {
|
||||
|
||||
public static function optionsForm($qt) {
|
||||
$form = array();
|
||||
$form['history'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => 'History',
|
||||
'#description' => t('Store tab state in the URL allowing for browser back / forward and bookmarks.'),
|
||||
'#default_value' => (isset($qt->renderer) && $qt->renderer == 'ui_tabs' && isset($qt->options['history']) && $qt->options['history']),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$quickset = $this->quickset;
|
||||
|
||||
$active_tab = $quickset->getActiveTab();
|
||||
$tabs = $this->build_tablinks($active_tab);
|
||||
$qt_name = $quickset->getName();
|
||||
$render_array = array(
|
||||
'#attached' => $this->add_attached(),
|
||||
'content' => array(
|
||||
'#theme' => 'qt_ui_tabs',
|
||||
'#options' => array('attributes' => array(
|
||||
'id' => 'quicktabs-' . $qt_name,
|
||||
'class' => 'quicktabs-ui-wrapper',
|
||||
)),
|
||||
'tabs' => array('#theme' => 'qt_ui_tabs_tabset', '#options' => array('active' => $active_tab), 'tablinks' => $tabs),
|
||||
'divs' => array(),
|
||||
),
|
||||
);
|
||||
foreach ($quickset->getContents() as $key => $tab) {
|
||||
if (!empty($tab)) {
|
||||
$attribs = array(
|
||||
'id' => 'qt-'. $qt_name .'-ui-tabs' . ($key+1),
|
||||
);
|
||||
$render_array['content']['divs'][] = array(
|
||||
'#prefix' => '<div '. drupal_attributes($attribs) .'>',
|
||||
'#suffix' => '</div>',
|
||||
'content' => $tab->render(),
|
||||
);
|
||||
}
|
||||
}
|
||||
return $render_array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build the actual tab links, with appropriate href, title and attributes.
|
||||
*
|
||||
* @param $active_tab The index of the active tab.
|
||||
*/
|
||||
protected function build_tablinks($active_tab) {
|
||||
$tabs = array();
|
||||
$qt_name = $this->quickset->getName();
|
||||
foreach ($this->quickset->getContents() as $i => $tab) {
|
||||
if (!empty($tab)) {
|
||||
// If we use l() here or a render array of type 'link', the '#' symbol will
|
||||
// be escaped. Sad panda is sad.
|
||||
$href = '#qt-'. $qt_name .'-ui-tabs' . ($i+1);
|
||||
$tablink = array(
|
||||
'#markup' => '<a href="'. $href .'">'. check_plain($this->quickset->translateString($tab->getTitle(), 'tab', $i)) .'</a>',
|
||||
);
|
||||
$tabs[$i] = $tablink;
|
||||
}
|
||||
}
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any necessary js, css and libraries for the render array.
|
||||
*/
|
||||
protected function add_attached() {
|
||||
$active_tab = $this->quickset->getActiveTab();
|
||||
$settings = $this->quickset->getSettings();
|
||||
$options = $settings['options'];
|
||||
|
||||
$attached = array(
|
||||
'library' => array(
|
||||
array('system', 'ui.tabs'),
|
||||
array('system', 'jquery.bbq'),
|
||||
),
|
||||
'js' => array(
|
||||
array('data' => drupal_get_path('module', 'quicktabs') . '/js/qt_ui_tabs.js', 'weight' => JS_DEFAULT + 1),
|
||||
),
|
||||
);
|
||||
|
||||
$javascript = drupal_add_js();
|
||||
foreach ($javascript['settings']['data'] as $key => $settings) {
|
||||
if (key($settings) == 'quicktabs') {
|
||||
$qtkey = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['history']) {
|
||||
$attached['library'][] = array('system', 'jquery.bbq');
|
||||
$attached['js'][] = array('data' => drupal_get_path('module', 'quicktabs') . '/js/quicktabs_bbq.js', 'weight' => JS_DEFAULT);
|
||||
}
|
||||
|
||||
$name = $this->quickset->getName();
|
||||
if (!isset($qtkey) || !array_key_exists('qt_' . $name, $javascript['settings']['data'][$qtkey]['quicktabs'])) {
|
||||
$quicktabs_array = array('name' => $name, 'active_tab' => $this->quickset->getActiveTab(), 'history' => $options['history']);
|
||||
$attached['js'][] = array('data' => array('quicktabs' => array('qt_'. $name => $quicktabs_array)), 'type' => 'setting');
|
||||
}
|
||||
return $attached;
|
||||
}
|
||||
}
|
141
sites/all/modules/quicktabs/plugins/QuickViewContent.inc
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for tab content of type "view" - this is for rendering a view as tab
|
||||
* content.
|
||||
*/
|
||||
class QuickViewContent extends QuickContent {
|
||||
|
||||
// Each view that we render, whether via ajax or not, will need a unique DOM
|
||||
// id. Unfortunately we can only control the ones that Quicktabs is responsible
|
||||
// for, so if there are other views on the page, there may be duplicate ids.
|
||||
static $view_dom_id = 1;
|
||||
|
||||
public static function getType() {
|
||||
return 'view';
|
||||
}
|
||||
|
||||
public function optionsForm($delta, $qt) {
|
||||
$tab = $this->settings;
|
||||
$form = array();
|
||||
$views = quicktabs_get_views();
|
||||
$views_keys = array_keys($views);
|
||||
|
||||
$selected_view = (isset($tab['vid']) ? $tab['vid'] : (isset($views_keys[0]) ? $views_keys[0] : ''));
|
||||
$form['view']['vid'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => $views,
|
||||
'#default_value' => $selected_view,
|
||||
'#title' => t('Select a view'),
|
||||
'#ajax' => array(
|
||||
'callback' => '_quicktabs_replace_view_displays_callback',
|
||||
),
|
||||
);
|
||||
$form['view']['display'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => 'display',
|
||||
'#options' => _quicktabs_get_views_displays($selected_view),
|
||||
'#default_value' => isset($tab['display']) ? $tab['display'] : '',
|
||||
'#prefix' => '<div id="view-display-dropdown-' . $delta . '">',
|
||||
'#suffix' => '</div>'
|
||||
);
|
||||
$form['view']['args'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => 'arguments',
|
||||
'#size' => '40',
|
||||
'#required' => FALSE,
|
||||
'#default_value' => isset($tab['args']) ? $tab['args'] : '',
|
||||
'#description' => t('Additional arguments to send to the view as if they were part of the URL in the form of arg1/arg2/arg3. You may use %0, %1, ..., %N to grab arguments from the URL.'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function __construct($item) {
|
||||
parent::__construct($item);
|
||||
if (module_exists('views')) views_add_js('ajax_view');
|
||||
$this->settings['view_path'] = rawurlencode($_GET['q']);
|
||||
$this->settings['view_dom_id'] = self::$view_dom_id++;
|
||||
if (isset($item['args'])) {
|
||||
$url_args = arg();
|
||||
$args = $item['args'];
|
||||
|
||||
foreach ($url_args as $id => $arg) {
|
||||
$args = str_replace("%$id", $arg, $args);
|
||||
}
|
||||
$args = preg_replace(',/?(%\d),', '', $args);
|
||||
if (!empty($args)) {
|
||||
$this->settings['ajax_args'] = rawurlencode($args);
|
||||
$args_array = explode('/', $args);
|
||||
}
|
||||
else {
|
||||
$this->settings['ajax_args'] = '';
|
||||
$args_array = array();
|
||||
}
|
||||
$this->settings['actual_args'] = $args_array;
|
||||
}
|
||||
}
|
||||
|
||||
public function render($hide_empty = FALSE, $args = array()) {
|
||||
if (!empty($args)) {
|
||||
// The args have been passed in from an ajax request. We use Views' own
|
||||
// ajax functionality to get the view.
|
||||
// The first element of the args array is the qt_name, which we don't need
|
||||
// for this content type.
|
||||
array_shift($args);
|
||||
// The order of these arguments corresponds to the array returned in
|
||||
// $this->getAjaxKeys().
|
||||
$_REQUEST['view_name'] = array_shift($args);
|
||||
$_REQUEST['view_display_id'] = array_shift($args);
|
||||
$_REQUEST['view_dom_id'] = array_shift($args);
|
||||
$view_path = array_shift($args);
|
||||
$_REQUEST['view_path'] = rawurldecode($view_path);
|
||||
if (!empty($args)) {
|
||||
$view_args = array_shift($args);
|
||||
$_REQUEST['view_args'] = rawurldecode($view_args);
|
||||
}
|
||||
|
||||
module_load_include('inc', 'views', 'includes/ajax');
|
||||
$view = views_ajax();
|
||||
foreach ($view['#commands'] as $command) {
|
||||
if ($command['command'] == 'insert') {
|
||||
return array('#markup' => trim($command['data']));
|
||||
}
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
// Non-ajax rendering of a view.
|
||||
if ($this->rendered_content) {
|
||||
return $this->rendered_content;
|
||||
}
|
||||
$item = $this->settings;
|
||||
$output = array();
|
||||
if (isset($item['vid'])) {
|
||||
if (module_exists('views')) {
|
||||
if ($view = views_get_view($item['vid'])) {
|
||||
if ($view->access($item['display'])) {
|
||||
$view->set_display($item['display']);
|
||||
$view->set_arguments($item['actual_args']);
|
||||
$view_output = $view->preview();
|
||||
if (!empty($view->result) || $view->display_handler->get_option('empty') || !empty($view->style_plugin->definition['even empty'])) {
|
||||
$output['#markup'] = $view_output;
|
||||
}
|
||||
}
|
||||
elseif (!$hide_empty) {
|
||||
$output['#markup'] = theme('quicktabs_tab_access_denied', array('tab' => $item));
|
||||
}
|
||||
$view->destroy();
|
||||
}
|
||||
}
|
||||
elseif (!$hide_empty) {
|
||||
$output['#markup'] = t('Views module is not enabled, cannot display content.');
|
||||
}
|
||||
}
|
||||
$this->rendered_content = $output;
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function getAjaxKeys() {
|
||||
return array('vid', 'display', 'view_dom_id', 'view_path', 'ajax_args');
|
||||
}
|
||||
}
|
658
sites/all/modules/quicktabs/quicktabs.admin.inc
Normal file
@@ -0,0 +1,658 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Provides the Quicktabs administrative interface.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Page callback to list quicktabs in the system.
|
||||
*/
|
||||
function quicktabs_list() {
|
||||
$header = array(
|
||||
array('data' => t('QuickSet')),
|
||||
array('data' => t('Storage')),
|
||||
array('data' => t('Operations'), 'colspan' => 4),
|
||||
);
|
||||
$rows = array();
|
||||
|
||||
foreach (quicktabs_load_multiple() as $qt) {
|
||||
// Determine storage
|
||||
switch ($qt->export_type) {
|
||||
case EXPORT_IN_DATABASE | EXPORT_IN_CODE:
|
||||
$storage = t('Overridden');
|
||||
$delete = l(t('Revert'), 'admin/structure/quicktabs/manage/'. $qt->machine_name .'/delete');
|
||||
break;
|
||||
case EXPORT_IN_DATABASE:
|
||||
$storage = t('Normal');
|
||||
$delete = l(t('Delete'), 'admin/structure/quicktabs/manage/'. $qt->machine_name .'/delete');
|
||||
break;
|
||||
case EXPORT_IN_CODE:
|
||||
$storage = t('Default');
|
||||
$delete = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$tablerow = array(
|
||||
array('data' => check_plain($qt->title)),
|
||||
array('data' => $storage),
|
||||
array('data' => l(t('Edit'), 'admin/structure/quicktabs/manage/'. $qt->machine_name .'/edit')),
|
||||
array('data' => l(t('Export'), 'admin/structure/quicktabs/manage/'. $qt->machine_name .'/export')),
|
||||
array('data' => l(t('Clone'), 'admin/structure/quicktabs/manage/'. $qt->machine_name .'/clone')),
|
||||
array('data' => $delete),
|
||||
);
|
||||
$rows[] = $tablerow;
|
||||
}
|
||||
|
||||
if (empty($rows)) {
|
||||
$rows[] = array(array('data' => t('No quicktabs instances available.'), 'colspan' => 6));
|
||||
}
|
||||
|
||||
$build = array(
|
||||
'#theme' => 'table',
|
||||
'#header' => $header,
|
||||
'#rows' => $rows,
|
||||
'#attributes' => array('id' => 'quicktabs'),
|
||||
);
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone QuickTabs.
|
||||
*/
|
||||
function quicktabs_clone($qt) {
|
||||
unset($qt->machine_name);
|
||||
$qt->title = '';
|
||||
return drupal_get_form('quicktabs_form', 'clone', $qt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the quicktab creation and edit form.
|
||||
*/
|
||||
function quicktabs_form($form, $form_state, $formtype, $qt = NULL) {
|
||||
if (!isset($qt)) {
|
||||
$qt = new stdClass;
|
||||
}
|
||||
$form = _quicktabs_admin_main_form($form_state, $qt);
|
||||
|
||||
// If creating a new Quicktabs instance, start off with 2 empty tabs.
|
||||
if (empty($qt->tabs)) {
|
||||
$qt->tabs = array(
|
||||
0 => array(),
|
||||
1 => array(),
|
||||
);
|
||||
}
|
||||
|
||||
// If the "Add another" button was clicked, we need to increment the number of
|
||||
// tabs by one.
|
||||
if (isset($form_state['num_tabs']) && $form_state['num_tabs'] > count($qt->tabs)) {
|
||||
$qt->tabs[] = array();
|
||||
}
|
||||
$form_state['num_tabs'] = count($qt->tabs);
|
||||
|
||||
// If the "Remove" button was clicked for a tab, we need to remove that tab
|
||||
// from the form.
|
||||
if (isset($form_state['to_remove'])) {
|
||||
unset($qt->tabs[$form_state['to_remove']]);
|
||||
unset($form_state['to_remove']);
|
||||
$form_state['num_tabs']--;
|
||||
}
|
||||
|
||||
$tab_titles = array();
|
||||
// Add current tabs to the form.
|
||||
foreach ($qt->tabs as $delta => $tab) {
|
||||
$tab['delta'] = $delta;
|
||||
$form['qt_wrapper']['tabs'][$delta] = _quicktabs_form($tab, $qt);
|
||||
if (isset($tab['title'])) {
|
||||
$tab_titles[$delta] = $tab['title'];
|
||||
}
|
||||
}
|
||||
// If there's only one tab, it shouldn't be removeable.
|
||||
if (count($qt->tabs) == 1) $form['qt_wrapper']['tabs'][$delta]['remove']['#access'] = FALSE;
|
||||
|
||||
$form['default_tab'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Default tab'),
|
||||
'#options' => $tab_titles,
|
||||
'#default_value' => isset($qt->default_tab) ? $qt->default_tab : 0,
|
||||
'#access' => !empty($tab_titles),
|
||||
'#weight' => -5,
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main section of admin page.
|
||||
*/
|
||||
function _quicktabs_admin_main_form($form_state, &$qt) {
|
||||
|
||||
// The contents of $qt will either come from the db or from $form_state.
|
||||
if (isset($form_state['values']['title'])) {
|
||||
$qt = _quicktabs_convert_form_to_quicktabs($form_state);
|
||||
}
|
||||
|
||||
$form['title'] = array(
|
||||
'#title' => t('Title'),
|
||||
'#description' => t('This will appear as the block title.'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => isset($qt->title) ? $qt->title : '',
|
||||
'#weight' => -9,
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
$form['machine_name'] = array(
|
||||
'#type' => 'machine_name',
|
||||
'#maxlength' => 32,
|
||||
'#machine_name' => array(
|
||||
'exists' => 'quicktabs_machine_name_exists',
|
||||
'source' => array('title'),
|
||||
),
|
||||
'#description' => t('A unique machine-readable name for this Quicktabs instance. It must only contain lowercase letters, numbers, and underscores. The machine name will be used internally by Quicktabs and will be used in the CSS ID of your Quicktabs block.'),
|
||||
'#weight' => -8,
|
||||
);
|
||||
|
||||
if (!empty($qt->machine_name)) {
|
||||
$form['machine_name']['#default_value'] = $qt->machine_name;
|
||||
$form['machine_name']['#disabled'] = TRUE;
|
||||
$form['machine_name']['#value'] = $qt->machine_name;
|
||||
}
|
||||
|
||||
ctools_include('plugins');
|
||||
$renderers = ctools_get_plugins('quicktabs', 'renderers');
|
||||
$renderer_options = array();
|
||||
foreach ($renderers as $name => $info) {
|
||||
if ($class = ctools_plugin_load_class('quicktabs', 'renderers', $name, 'handler')) {
|
||||
// Add the renderer to the dropdown list of renderers
|
||||
$renderer_options[$name] = $name;
|
||||
// Get the renderer's options form elements
|
||||
|
||||
// PHP 5.2 doesn't support $class::staticMethod() syntax, so we have to
|
||||
// use call_user_func_array() until PHP 5.3 is required.
|
||||
$renderer_form_options[$name] = call_user_func_array(array($class, 'optionsForm'), array($qt));
|
||||
}
|
||||
}
|
||||
ksort($renderer_options);
|
||||
$form['renderer'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Renderer'),
|
||||
'#options' => $renderer_options,
|
||||
'#default_value' => isset($qt->renderer) ? $qt->renderer : 'quicktabs',
|
||||
'#description' => t('Choose how to render the content.'),
|
||||
'#weight' => -7,
|
||||
);
|
||||
// Add the renderer options form elements to the form, to be shown only if the
|
||||
// renderer in question is selected.
|
||||
$form['options'] = array('#tree' => TRUE, '#weight' => -6);
|
||||
foreach ($renderer_form_options as $renderer => $options) {
|
||||
foreach ($options as &$option) {
|
||||
$option['#states'] = array('visible' => array(':input[name="renderer"]' => array('value' => $renderer)));
|
||||
}
|
||||
$form['options'][$renderer] = $options;
|
||||
}
|
||||
|
||||
$styles = module_invoke_all('quicktabs_tabstyles');
|
||||
if (count($styles)) {
|
||||
$style_options = array();
|
||||
// The keys used for options must be valid html IDs.
|
||||
foreach ($styles as $style) {
|
||||
$style_options[$style] = $style;
|
||||
}
|
||||
ksort($style_options);
|
||||
$form['style'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Style'),
|
||||
'#options' => array('nostyle' => t('No style')) + array('default' => t('Default style')) + $style_options,
|
||||
'#default_value' => isset($qt->style) ? $qt->style : 'default',
|
||||
'#description' => t('Choose the quicktab style.'),
|
||||
'#states' => array('visible' => array(':input[name="renderer"]' => array('value' => 'quicktabs'))),
|
||||
'#weight' => -6,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['style'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => 'nostyle',
|
||||
);
|
||||
}
|
||||
|
||||
$form['ajax'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Ajax'),
|
||||
'#options' => array(
|
||||
TRUE => t('Yes') . ': ' . t('Load only the first tab on page view'),
|
||||
FALSE => t('No') . ': ' . t('Load all tabs on page view.'),
|
||||
),
|
||||
'#default_value' => isset($qt->ajax) ? $qt->ajax : 0,
|
||||
'#description' => t('Choose how the content of tabs should be loaded.<p>By choosing "Yes", only the first tab will be loaded when the page first viewed. Content for other tabs will be loaded only when the user clicks the other tab. This will provide faster initial page loading, but subsequent tab clicks will be slower. This can place less load on a server.</p><p>By choosing "No", all tabs will be loaded when the page is first viewed. This will provide slower initial page loading, and more server load, but subsequent tab clicks will be faster for the user. Use with care if you have heavy views.</p><p>Warning: if you enable Ajax, any block you add to this quicktabs block will be accessible to anonymous users, even if you place role restrictions on the quicktabs block. Do not enable Ajax if the quicktabs block includes any blocks with potentially sensitive information.</p>'),
|
||||
'#states' => array('visible' => array(':input[name="renderer"]' => array('value' => 'quicktabs'))),
|
||||
'#weight' => -5,
|
||||
);
|
||||
|
||||
$form['hide_empty_tabs'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Hide empty tabs'),
|
||||
'#default_value' => isset($qt->hide_empty_tabs) ? $qt->hide_empty_tabs : 0,
|
||||
'#description' => t('Empty and restricted tabs will not be displayed. Could be useful when the tab content is not accessible.<br />This option does not work in ajax mode.'),
|
||||
'#weight' => -4,
|
||||
);
|
||||
|
||||
// Add a wrapper for the tabs and Add Another Tab button.
|
||||
$form['qt_wrapper'] = array(
|
||||
'#tree' => FALSE,
|
||||
'#weight' => -3,
|
||||
'#prefix' => '<div class="clear-block" id="quicktabs-tabs-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
|
||||
$form['qt_wrapper']['tabs'] = array(
|
||||
'#tree' => TRUE,
|
||||
'#prefix' => '<div id="quicktab-tabs">',
|
||||
'#suffix' => '</div>',
|
||||
'#theme' => 'quicktabs_admin_form_tabs',
|
||||
);
|
||||
|
||||
$form['qt_wrapper']['tabs_more'] = array(
|
||||
'#type' => 'submit',
|
||||
'#prefix' => '<div id="add-more-tabs-button">',
|
||||
'#suffix' => '<label for="edit-tabs-more">' . t('Add tab') . '</label></div>',
|
||||
'#value' => t('More tabs'),
|
||||
'#attributes' => array('class' => array('add-tab'), 'title' => t('Click here to add more tabs.')),
|
||||
'#weight' => 1,
|
||||
'#submit' => array('quicktabs_more_tabs_submit'),
|
||||
'#ajax' => array(
|
||||
'callback' => 'quicktabs_ajax_callback',
|
||||
'wrapper' => 'quicktab-tabs',
|
||||
'effect' => 'fade',
|
||||
),
|
||||
'#limit_validation_errors' => array(),
|
||||
);
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit_form'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build one row (one tabpage) on the QT admin form.
|
||||
*
|
||||
* @param array $tab
|
||||
* An array containing the details of this particular tabpage.
|
||||
*
|
||||
* @param object $qt
|
||||
* An object representing the Quicktabs instance that the tabs are
|
||||
* being built for.
|
||||
*/
|
||||
function _quicktabs_form(array $tab, $qt) {
|
||||
$form['#tree'] = TRUE;
|
||||
$delta = $tab['delta'];
|
||||
|
||||
$form['weight'] = array(
|
||||
'#type' => 'weight',
|
||||
'#default_value' => isset($tab['weight']) ? $tab['weight'] : $delta-100,
|
||||
'#delta' => 100,
|
||||
);
|
||||
|
||||
$form['title'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => '10',
|
||||
'#default_value' => isset($tab['title']) ? $tab['title'] : '',
|
||||
);
|
||||
|
||||
// Load all "contents" plugins to display a choice of content types.
|
||||
ctools_include('plugins');
|
||||
$contents = ctools_get_plugins('quicktabs', 'contents');
|
||||
foreach ($contents as $name => $info) {
|
||||
if (isset($info['dependencies'])) {
|
||||
foreach ($info['dependencies'] as $dep) {
|
||||
// Do not load the options form for any plugin that is missing dependencies.
|
||||
if (!module_exists($dep)) continue 2;
|
||||
}
|
||||
}
|
||||
$tabtypes[$name] = $name;
|
||||
$content_provider = quick_content_factory($name, $tab);
|
||||
$form = array_merge_recursive($form, $content_provider->optionsForm($delta, $qt));
|
||||
}
|
||||
|
||||
$form['type'] = array(
|
||||
'#type' => 'radios',
|
||||
'#options' => $tabtypes,
|
||||
'#default_value' => isset($tab['type']) ? $tab['type'] : key($tabtypes),
|
||||
);
|
||||
|
||||
$form['remove'] = array(
|
||||
'#type' => 'submit',
|
||||
'#prefix' => '<div>',
|
||||
'#suffix' => '<label for="edit-remove">' . t('Delete') . '</label></div>',
|
||||
'#value' => 'remove_' . $delta,
|
||||
'#attributes' => array('class' => array('delete-tab'), 'title' => t('Click here to delete this tab.')),
|
||||
'#submit' => array('quicktabs_remove_tab_submit'),
|
||||
'#ajax' => array(
|
||||
'callback' => 'quicktabs_ajax_callback',
|
||||
'wrapper' => 'quicktab-tabs',
|
||||
'method' => 'replace',
|
||||
'effect' => 'fade',
|
||||
),
|
||||
'#limit_validation_errors' => array(),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function for quicktabs admin page.
|
||||
* Theme the form elements for the tabs as draggable table rows.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_quicktabs_admin_form_tabs($variables) {
|
||||
$tabs = $variables['tabs'];
|
||||
|
||||
drupal_add_tabledrag('qt-tablist-table', 'order', 'sibling', 'qt-tabs-weight');
|
||||
$rows = array();
|
||||
$header = array(
|
||||
t('Tab title'),
|
||||
t('Tab weight'),
|
||||
t('Tab type'),
|
||||
t('Tab content'),
|
||||
t('Operations'),
|
||||
);
|
||||
|
||||
foreach (element_children($tabs) as $key) {
|
||||
$tab = &$tabs[$key];
|
||||
$tab['weight']['#attributes']['class'] = array('qt-tabs-weight');
|
||||
|
||||
// tab settings fields
|
||||
$tab_fields = array(
|
||||
array('data' => drupal_render($tab['title']), 'class' => array('qt-tab-title')),
|
||||
array('data' => drupal_render($tab['weight']), 'class' => array('qt-tab-weight')),
|
||||
array('data' => drupal_render($tab['type']), 'class' => array('qt-tab-type')),
|
||||
);
|
||||
|
||||
// content plugins
|
||||
$content_plugins = '';
|
||||
foreach ($tab['type']['#options'] as $content_provider ) {
|
||||
$tab[$content_provider]['#prefix'] = '<div class="qt-tab-options-form qt-tab-'. $content_provider .'-options-form">';
|
||||
$tab[$content_provider]['#suffix'] = '</div>';
|
||||
$content_plugins .= drupal_render($tab[$content_provider]);
|
||||
}
|
||||
$tab_fields[] = array('data' => $content_plugins);
|
||||
$tab_fields[] = array('data' => drupal_render($tab['remove']), 'class' => array('qt-tab-remove'));
|
||||
|
||||
// Build the table row.
|
||||
$row = array(
|
||||
'data' => $tab_fields,
|
||||
'class' => array('draggable'),
|
||||
);
|
||||
|
||||
// Add additional attributes to the row, such as a class for this row.
|
||||
if (isset($tab['#attributes'])) {
|
||||
$row = array_merge($row, $tab['#attributes']);
|
||||
}
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$build['quicktab'] = array(
|
||||
'#theme' => 'table',
|
||||
'#header' => $header,
|
||||
'#rows' => $rows,
|
||||
'#attributes' => array('id' => 'qt-tablist-table'),
|
||||
'#weight' => -1,
|
||||
);
|
||||
$build['#attached']['css'][] = drupal_get_path('module', 'quicktabs') . '/css/quicktabs-admin.css';
|
||||
$build['#attached']['js'][] = drupal_get_path('module', 'quicktabs') . '/js/quicktabs_form.js';
|
||||
|
||||
$output = drupal_render($build);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for the add tab and remove tab buttons.
|
||||
*/
|
||||
function quicktabs_ajax_callback($form, $form_state) {
|
||||
$form_tabs = $form['qt_wrapper']['tabs'];
|
||||
return $form_tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the "Add Tab" button.
|
||||
*/
|
||||
function quicktabs_more_tabs_submit($form, &$form_state) {
|
||||
// Increment the number of tabs to be rendered.
|
||||
$form_state['num_tabs']++;
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the "Remove Tab" button.
|
||||
*/
|
||||
function quicktabs_remove_tab_submit($form, &$form_state) {
|
||||
// Get the tab delta for the clicked button.
|
||||
$delta = $form_state['clicked_button']['#parents'][1];
|
||||
$form_state['to_remove'] = $delta;
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation handler for quicktabs admin page.
|
||||
*/
|
||||
function quicktabs_form_validate($form, &$form_state) {
|
||||
if (empty($form_state['values']['machine_name'])) {
|
||||
form_set_error('machine_name', t('The quicktabs machine name is required.'));
|
||||
}
|
||||
elseif (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['machine_name'])) {
|
||||
form_set_error('machine_name', t('The quicktabs machine name must contain only lowercase letters, numbers, and underscores.'));
|
||||
}
|
||||
|
||||
if (!isset($form_state['values']['tabs'])) {
|
||||
form_set_error('', t('At least one tab should be created.'));
|
||||
}
|
||||
else {
|
||||
foreach ($form_state['values']['tabs'] as $j => $tab) {
|
||||
if (empty($tab['title'])) {
|
||||
form_set_error('tabs][' . $j . '][title', t('Title is required for each tab.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function quicktabs_callback_element_validate($element, &$form_state, $form) {
|
||||
// We can tell which tab delta the element is for from the element's #parents
|
||||
// property, which is an array based on the tree structure.
|
||||
$delta = $element['#parents'][1];
|
||||
if ($form_state['values']['tabs'][$delta]['type'] == 'callback') {
|
||||
if (empty($element['#value']) || url_is_external($element['#value'])) {
|
||||
form_error($element, t('You must specify a valid path.'));
|
||||
}
|
||||
if (strpos($element['#value'], '%') === 0) {
|
||||
form_error($element, t('"%" may not be used for the first segment of a path.'));
|
||||
}
|
||||
// automatically remove '/' from path.
|
||||
$form_state['values']['tabs'][$delta]['callback']['path'] = trim($form_state['values']['tabs'][$delta]['callback']['path'], '/');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Submit handler for quicktabs admin page.
|
||||
*/
|
||||
function quicktabs_form_submit($form, &$form_state) {
|
||||
if ($form_state['clicked_button']['#id'] == 'edit-submit-form') {
|
||||
$qt = _quicktabs_convert_form_to_quicktabs($form_state);
|
||||
|
||||
$exists = quicktabs_load($qt->machine_name);
|
||||
if ($exists && empty($exists->in_code_only)) {
|
||||
$ret = drupal_write_record('quicktabs', $qt, 'machine_name');
|
||||
if ($ret == SAVED_UPDATED) {
|
||||
drupal_set_message(t('The Quicktabs instance has been updated.'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$ret = drupal_write_record('quicktabs', $qt);
|
||||
if ($ret == SAVED_NEW) {
|
||||
drupal_set_message(t('The Quicktabs instance has been created.'));
|
||||
}
|
||||
}
|
||||
quicktabs_i18n_update_strings(array($qt->machine_name));
|
||||
drupal_goto('admin/structure/quicktabs');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletion of quicktab block.
|
||||
*/
|
||||
function quicktabs_block_delete($form, $form_state, $qt) {
|
||||
$form['machine_name'] = array('#type' => 'hidden', '#value' => $qt->machine_name);
|
||||
$form['title'] = array('#type' => 'hidden', '#value' => $qt->title);
|
||||
return confirm_form($form, t('Are you sure you want to delete the quicktab block %title?', array('%title' => $qt->title)), 'admin/structure/quicktabs', '', t('Delete'), t('Cancel'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for quicktab block deletion.
|
||||
*/
|
||||
function quicktabs_block_delete_submit($form, &$form_state) {
|
||||
db_query('DELETE FROM {quicktabs} WHERE machine_name = :machine_name', array(':machine_name' => $form_state['values']['machine_name']));
|
||||
drupal_set_message(t('The Quicktabs instance %name has been removed.', array('%name' => $form_state['values']['title'])));
|
||||
cache_clear_all();
|
||||
$form_state['redirect'] = 'admin/structure/quicktabs';
|
||||
};
|
||||
|
||||
/**
|
||||
* Export form for quicktabs.
|
||||
*/
|
||||
function quicktabs_export_form($form, &$form_state, $qt) {
|
||||
ctools_include('export');
|
||||
// Generate export code
|
||||
$code = '$items = array();' ."\n";
|
||||
$code .= ctools_export_object('quicktabs', $qt, '');
|
||||
$code .= '$items["'. $qt->machine_name .'"] = $quicktabs;' ."\n";
|
||||
$code .= 'return $items;';
|
||||
|
||||
// Create form
|
||||
$form = array();
|
||||
$form['export'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#default_value' => $code,
|
||||
'#rows' => substr_count($code, "\n") + 1,
|
||||
'#resizable' => FALSE,
|
||||
'#description' => t('Place this code in your module\'s implementation of <code>hook_quicktabs_default_quicktabs()</code> to provide it as a default quicktab.'),
|
||||
);
|
||||
$form['done'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Done'),
|
||||
);
|
||||
$form['#redirect'] = 'admin/structure/quicktabs';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get all blocks.
|
||||
*/
|
||||
function quicktabs_get_blocks() {
|
||||
$blocksarray = &drupal_static(__FUNCTION__, array());
|
||||
if (empty($blocksarray)) {
|
||||
$blocks = _block_rehash();
|
||||
$blocksarray = array();
|
||||
foreach ($blocks as $block) {
|
||||
if ($block['module'] != 'quicktabs') {
|
||||
$key = $block['module'] . '_delta_' . $block['delta'];
|
||||
$blocksarray[$key] = $block['info'] . ' (' . $block['module'] . ':' . $block['delta'] . ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $blocksarray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback, triggered when view is changed.
|
||||
*/
|
||||
function _quicktabs_replace_view_displays_callback($form, $form_state) {
|
||||
$view_name = $form_state['triggering_element']['#value'];
|
||||
$delta = $form_state['triggering_element']['#parents'][1];
|
||||
$display_options = _quicktabs_get_views_displays($view_name);
|
||||
$form['qt_wrapper']['tabs'][$delta]['view']['display']['#options'] = $display_options;
|
||||
|
||||
$commands = array();
|
||||
// Replace the view display dropdown.
|
||||
$commands[] = ajax_command_replace("#view-display-dropdown-$delta", drupal_render($form['qt_wrapper']['tabs'][$delta]['view']['display']));
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get all views.
|
||||
*/
|
||||
function quicktabs_get_views() {
|
||||
$enabled_views = array();
|
||||
$views = views_get_all_views();
|
||||
|
||||
foreach ($views as $view) {
|
||||
// Skip disabled views.
|
||||
if (!empty($views[$view->name]->disabled)) {
|
||||
continue;
|
||||
}
|
||||
$enabled_views[$view->name] = $view->name;
|
||||
}
|
||||
ksort($enabled_views);
|
||||
return $enabled_views;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get all view displays.
|
||||
*/
|
||||
function _quicktabs_get_views_displays($view_name) {
|
||||
$displays = array();
|
||||
if (empty($view_name)) {
|
||||
// No view.
|
||||
return $displays;
|
||||
}
|
||||
|
||||
$views = views_get_all_views();
|
||||
$view = $views[$view_name];
|
||||
|
||||
if (empty($view->display)) {
|
||||
// This view is broken.
|
||||
return $displays;
|
||||
}
|
||||
|
||||
foreach ($view->display as $id => $display) {
|
||||
$displays[$id] = $id .': '. $display->display_title;
|
||||
}
|
||||
return $displays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to convert the data on admin form into quicktab presentation.
|
||||
*/
|
||||
function _quicktabs_convert_form_to_quicktabs($form_state) {
|
||||
$formvalues_tabs = array();
|
||||
if (!empty($form_state['values']['tabs'])) {
|
||||
foreach ($form_state['values']['tabs'] as $j => $tab) {
|
||||
$formvalues_tabs[$j] = $tab[$tab['type']];
|
||||
$formvalues_tabs[$j]['title'] = $tab['title'];
|
||||
$formvalues_tabs[$j]['weight'] = $tab['weight'];
|
||||
$formvalues_tabs[$j]['type'] = $tab['type'];
|
||||
$weight[$j] = $tab['weight'];
|
||||
}
|
||||
array_multisort($weight, SORT_ASC, $formvalues_tabs);
|
||||
}
|
||||
$renderer = $form_state['values']['renderer'];
|
||||
$qt = new stdClass();
|
||||
$qt->title = $form_state['values']['title'];
|
||||
$qt->ajax = $form_state['values']['ajax'];
|
||||
$qt->default_tab = isset($form_state['values']['default_tab']) ? $form_state['values']['default_tab'] : 0;
|
||||
$qt->hide_empty_tabs = $form_state['values']['hide_empty_tabs'];
|
||||
$qt->renderer = $renderer;
|
||||
$qt->style = $form_state['values']['style'];
|
||||
$qt->tabs = $formvalues_tabs;
|
||||
$qt->options = isset($form_state['values']['options'][$renderer]) ? $form_state['values']['options'][$renderer] : array();
|
||||
|
||||
if (isset($form_state['values']['machine_name'])) {
|
||||
$qt->machine_name = $form_state['values']['machine_name'];
|
||||
}
|
||||
|
||||
return $qt;
|
||||
}
|
23
sites/all/modules/quicktabs/quicktabs.api.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Alter the Quicktabs instance before it gets rendered.
|
||||
*
|
||||
* @param &$quicktabs
|
||||
* A loaded Quicktabs object, either from the database or from code.
|
||||
*/
|
||||
function hook_quicktabs_alter(&$quicktabs) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This hook allows other modules to create additional tab styles for
|
||||
* the quicktabs module.
|
||||
*
|
||||
* @return array
|
||||
* An array of key => value pairs suitable for inclusion as the #options in a
|
||||
* select or radios form element. Each key must be the location of a css
|
||||
* file for a quick tabs style. Each value should be the name of the style.
|
||||
*/
|
||||
function hook_quicktabs_tabstyles() {
|
||||
}
|
||||
|
516
sites/all/modules/quicktabs/quicktabs.classes.inc
Normal file
@@ -0,0 +1,516 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A QuickSet object is an unrendered Quicktabs instance, essentially just a
|
||||
* container of content items, as defined by its configuration settings and the
|
||||
* array of content items it contains.
|
||||
*/
|
||||
class QuickSet {
|
||||
|
||||
/**
|
||||
* The unique name of the QuickSet object.
|
||||
* This corresponds to the machine name as stored in the database or as defined
|
||||
* in code.
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The contents array.
|
||||
* An array of objects that implement the QuickContentRenderable interface.
|
||||
* @var array
|
||||
*/
|
||||
protected $contents;
|
||||
|
||||
/**
|
||||
* An array of settings controlling the behaviour of the QuickSet object. See
|
||||
* the getDefaultSettings() static function of this class for the full list of
|
||||
* settings.
|
||||
* @var array
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
|
||||
/**
|
||||
* Accessors.
|
||||
*/
|
||||
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getContents() {
|
||||
return $this->contents;
|
||||
}
|
||||
|
||||
public function getSettings() {
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return isset($this->settings['title']) ? $this->translateString($this->settings['title'], 'title') : $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate, populate and return a QuickSet object wrapped in a renderer.
|
||||
*
|
||||
* @param $name
|
||||
* The unique name (machine name) of the QuickSet instance.
|
||||
*
|
||||
* @param $contents
|
||||
* The array of content items, each one itself an array with at least a 'type'
|
||||
* key, a 'title' key, and the other info necessary for that type.
|
||||
*
|
||||
* @param $renderer
|
||||
* The plugin key for this renderer plugin
|
||||
*
|
||||
* @param $settings
|
||||
* An array of settings determining the behaviour of this QuickSet instance.
|
||||
*
|
||||
*/
|
||||
public static function QuickSetRendererFactory($name, $contents, $renderer, $settings) {
|
||||
ctools_include('plugins');
|
||||
if ($class = ctools_plugin_load_class('quicktabs', 'renderers', $renderer, 'handler')) {
|
||||
try {
|
||||
$qs = new self($name, $contents, $settings);
|
||||
}
|
||||
catch (InvalidQuickSetException $e) {
|
||||
watchdog('Quicktabs', $e->getMessage());
|
||||
return NULL;
|
||||
}
|
||||
return new $class($qs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to an object that implements the QuickContentRenderable
|
||||
* interface.
|
||||
*/
|
||||
public static function getContentRenderer($tab) {
|
||||
if ($tab['type'] == 'prerendered') {
|
||||
return new QuickPreRenderedContent($tab);
|
||||
}
|
||||
if ($content = QuickContent::factory($tab['type'], $tab)) {
|
||||
return $content;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to retrieve content from an ajax call. This is called by the
|
||||
* quicktabs_ajax() callback in quicktabs.module.
|
||||
*/
|
||||
public static function ajaxRenderContent($type, $args) {
|
||||
if ($renderer = self::getContentRenderer(array('type' => $type))) {
|
||||
$output = $renderer->render(FALSE, $args);
|
||||
return !empty($output) ? drupal_render($output) : '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure sensible default settings for each QuickSet object.
|
||||
*/
|
||||
private static function getDefaultSettings() {
|
||||
return array(
|
||||
'title' => '<none>',
|
||||
'style' => 'nostyle',
|
||||
'hide_empty_tabs' => 0,
|
||||
'ajax' => 0,
|
||||
'default_tab' => 0,
|
||||
'options' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($name, $contents, $settings) {
|
||||
$this->name = $name;
|
||||
$this->contents = array();
|
||||
foreach ($contents as $key => $item) {
|
||||
// Instantiate a content renderer object and add it to the contents array.
|
||||
if ($renderer = self::getContentRenderer($item)) {
|
||||
$this->contents[$key] = $renderer;
|
||||
}
|
||||
}
|
||||
$default_settings = self::getDefaultSettings();
|
||||
$this->settings = array_merge($default_settings, $settings);
|
||||
|
||||
$this->prepareContents();
|
||||
// Set the default style if necessary.
|
||||
if ($this->settings['style'] == 'default') {
|
||||
$this->settings['style'] = variable_get('quicktabs_tabstyle', 'nostyle');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ajax path to be used on ajax-enabled tab links.
|
||||
*
|
||||
* @param $index The index of the tab, i.e where it fits into the QuickSet
|
||||
* instance.
|
||||
*
|
||||
* @param $type The type of content we are providing an ajax path for.
|
||||
*/
|
||||
public function getAjaxPath($index, $type) {
|
||||
return 'quicktabs/ajax/'. $this->name .'/'. $index . '/'. $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates Quicktabs user-defined strings if the i18n module is
|
||||
* enabled.
|
||||
*/
|
||||
public function translateString($string, $type = 'tab', $index = 0) {
|
||||
switch ($type) {
|
||||
case 'tab':
|
||||
$name = "tab:{$this->name}-{$index}:title";
|
||||
break;
|
||||
case 'title':
|
||||
$name = "title:{$this->name}";
|
||||
break;
|
||||
}
|
||||
return quicktabs_translate($name, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does some initial set-up of the tab contents, such as hiding
|
||||
* tabs with no content if the hide_empty_tabs option is set. It also makes sure
|
||||
* that prerendered contents are never attempted to be loaded via ajax.
|
||||
*
|
||||
* @throws InvalidQuickSetException if there are no contents to render.
|
||||
*/
|
||||
protected function prepareContents() {
|
||||
if (!count($this->contents)) {
|
||||
throw new InvalidQuickSetException('There are no contents to render.');
|
||||
}
|
||||
if ($this->settings['hide_empty_tabs'] && !$this->settings['ajax']) {
|
||||
// Check if any tabs need to be hidden because of empty content.
|
||||
$renderable_contents = 0;
|
||||
foreach ($this->contents as $key => $tab) {
|
||||
$contents = $tab->render(TRUE);
|
||||
if (empty($contents)) {
|
||||
// Rather than removing the item, we set it to NULL. This way we retain
|
||||
// the same indices across tabs, so that permanent links to particular
|
||||
// tabs can be relied upon.
|
||||
$this->contents[$key] = NULL;
|
||||
// The default tab must not be a hidden tab.
|
||||
if ($this->settings['default_tab'] == $key) {
|
||||
$this->settings['default_tab'] = ($key + 1) % count($this->contents);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$renderable_contents++;
|
||||
}
|
||||
}
|
||||
if (!$renderable_contents) {
|
||||
throw new InvalidQuickSetException('There are no contents to render.');
|
||||
}
|
||||
}
|
||||
elseif ($this->settings['ajax']) {
|
||||
// Make sure that there is at most 1 prerendered tab and it is the default tab.
|
||||
// Prerendered content cannot be rendered via ajax.
|
||||
$has_prerendered = FALSE; // keep track of whether we have found a prerendered tab.
|
||||
foreach ($this->contents as $key => $tab) {
|
||||
$type = $tab->getType();
|
||||
if ($type == 'prerendered') {
|
||||
if (!$has_prerendered) {
|
||||
$has_prerendered = TRUE;
|
||||
$this->settings['default_tab'] = $key;
|
||||
// In the case of a direct link to a different tab, the 'default_tab'
|
||||
// will be overridden, so we need to make sure it does not attempt
|
||||
// to load a pre-rendered tab via ajax. Turn ajax option off.
|
||||
if ($this->getActiveTab() !== $key) {
|
||||
$this->settings['ajax'] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We are on a second custom tab and the ajax option is set, we cannot
|
||||
// render custom tabs via ajax, so we skip out of the loop, set the
|
||||
// ajax option to off, and call the method again.
|
||||
$this->settings['ajax'] = 0;
|
||||
$this->prepareContents();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the active tab for a given Quicktabs instance. This could be coming
|
||||
* from the URL or just from the settings for this instance. If neither, it
|
||||
* defaults to 0.
|
||||
*/
|
||||
public function getActiveTab() {
|
||||
$active_tab = isset($this->settings['default_tab']) ? $this->settings['default_tab'] : key($this->contents);
|
||||
$active_tab = isset($_GET['qt-' . $this->name]) ? $_GET['qt-' . $this->name] : $active_tab;
|
||||
$active_tab = (isset($active_tab) && isset($this->contents[$active_tab])) ? $active_tab : 0;
|
||||
return $active_tab;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base class for QuickSet Renderers.
|
||||
*
|
||||
* A renderer object contains a reference to a QuickSet object, which it can
|
||||
* then render.
|
||||
*/
|
||||
abstract class QuickRenderer {
|
||||
|
||||
/**
|
||||
* @var QuickSet
|
||||
*/
|
||||
protected $quickset;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($quickset) {
|
||||
$this->quickset = $quickset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor method for the title.
|
||||
*/
|
||||
public function getTitle() {
|
||||
return $this->quickset->getTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* The only method that renderer plugins must implement.
|
||||
*
|
||||
* @return A render array to be passed to drupal_render().
|
||||
*/
|
||||
abstract public function render();
|
||||
|
||||
|
||||
/**
|
||||
* Method for returning the form elements to display for this renderer type on
|
||||
* the admin form.
|
||||
|
||||
* @param $qt An object representing the Quicktabs instance that the tabs are
|
||||
* being built for.
|
||||
*/
|
||||
public static function optionsForm($qt) {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************
|
||||
* The classes below relate to individual tab content *
|
||||
*******************************************************/
|
||||
|
||||
/**
|
||||
* Each QuickSet object has a "contents" property which is an array of objects
|
||||
* that implement the QuickContentRenderable interface.
|
||||
*/
|
||||
interface QuickContentRenderable {
|
||||
|
||||
/**
|
||||
* Returns the short type name of the content plugin, e.g. 'block', 'node',
|
||||
* 'prerendered'.
|
||||
*/
|
||||
public static function getType();
|
||||
|
||||
/**
|
||||
* Returns the tab title.
|
||||
*/
|
||||
public function getTitle();
|
||||
|
||||
/**
|
||||
* Returns an array of settings specific to the type of content.
|
||||
*/
|
||||
public function getSettings();
|
||||
|
||||
/**
|
||||
* Renders the content.
|
||||
*
|
||||
* @param $hide_emtpy If set to true, then the renderer should return an empty
|
||||
* array if there is no content to display, for example if the user does not
|
||||
* have access to the requested content.
|
||||
*
|
||||
* @param $args Used during an ajax call to pass in the settings necessary to
|
||||
* render this type of content.
|
||||
*/
|
||||
public function render($hide_empty = FALSE, $args = array());
|
||||
|
||||
/**
|
||||
* Returns an array of keys to use for constructing the correct arguments for
|
||||
* an ajax callback to retrieve content of this type. The order of the keys
|
||||
* returned affects the order of the args passed in to the render method when
|
||||
* called via ajax (see the render() method above).
|
||||
*/
|
||||
public function getAjaxKeys();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base class for content plugins.
|
||||
*/
|
||||
abstract class QuickContent implements QuickContentRenderable {
|
||||
|
||||
/**
|
||||
* Used as the title of the tab.
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* An array containing the information that defines the tab content, specific
|
||||
* to its type.
|
||||
* @var array
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* A render array of the contents.
|
||||
* @var array
|
||||
*/
|
||||
protected $rendered_content;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($item) {
|
||||
$this->title = isset($item['title']) ? $item['title'] : '';
|
||||
// We do not need to store title, type or weight in the settings array, which
|
||||
// is for type-specific settings.
|
||||
unset($item['title'], $item['type'], $item['weight']);
|
||||
$this->settings = $item;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Accessor for the tab title.
|
||||
*/
|
||||
public function getTitle() {
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the tab settings.
|
||||
*/
|
||||
public function getSettings() {
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a content type object.
|
||||
*
|
||||
* @param $name
|
||||
* The type name of the plugin.
|
||||
*
|
||||
* @param $item
|
||||
* An array containing the item definition
|
||||
*
|
||||
*/
|
||||
public static function factory($name, $item) {
|
||||
ctools_include('plugins');
|
||||
if ($class = ctools_plugin_load_class('quicktabs', 'contents', $name, 'handler')) {
|
||||
// We now need to check the plugin's dependencies, to make sure they're installed.
|
||||
// This info has already been statically cached at this point so there's no
|
||||
// harm in making a call to ctools_get_plugins().
|
||||
$plugin = ctools_get_plugins('quicktabs', 'contents', $name);
|
||||
if (isset($plugin['dependencies'])) {
|
||||
foreach ($plugin['dependencies'] as $dep) {
|
||||
// If any dependency is missing we cannot instantiate our class.
|
||||
if (!module_exists($dep)) return NULL;
|
||||
}
|
||||
}
|
||||
return new $class($item);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for returning the form elements to display for this tab type on
|
||||
* the admin form.
|
||||
*
|
||||
* @param $delta Integer representing this tab's position in the tabs array.
|
||||
*
|
||||
* @param $qt An object representing the Quicktabs instance that the tabs are
|
||||
* being built for.
|
||||
*/
|
||||
abstract public function optionsForm($delta, $qt);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This class implements the same interface that content plugins do but it is not
|
||||
* a content plugin. It is a special class for pre-rendered content which is used
|
||||
* when "custom" tabs are added to existing Quicktabs instances in a call to
|
||||
* quicktabs_build_quicktabs().
|
||||
*/
|
||||
class QuickPreRenderedContent implements QuickContentRenderable {
|
||||
|
||||
public static function getType() {
|
||||
return 'prerendered';
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as the title of the tab.
|
||||
* @var title
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* A render array of the contents.
|
||||
* @var array
|
||||
*/
|
||||
protected $rendered_content;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($item) {
|
||||
|
||||
$contents = isset($item['contents']) ? $item['contents'] : array();
|
||||
if (!is_array($contents)) {
|
||||
$contents = array('#markup' => $contents);
|
||||
}
|
||||
$this->rendered_content = $contents;
|
||||
|
||||
$this->title = isset($item['title']) ? $item['title'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the tab title.
|
||||
*/
|
||||
public function getTitle() {
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prerendered content doesn't need any extra settings.
|
||||
*/
|
||||
public function getSettings() {
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The render method simply returns the contents that were passed in and
|
||||
* stored during construction.
|
||||
*/
|
||||
public function render($hide_empty = FALSE, $args = array()) {
|
||||
return $this->rendered_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* This content cannot be rendered via ajax so we don't return any ajax keys.
|
||||
*/
|
||||
public function getAjaxKeys() {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create our own exception class.
|
||||
*/
|
||||
class InvalidQuickSetException extends Exception {
|
||||
|
||||
}
|
16
sites/all/modules/quicktabs/quicktabs.info
Normal file
@@ -0,0 +1,16 @@
|
||||
name = Quicktabs
|
||||
description = Render content with tabs and other display styles
|
||||
core = 7.x
|
||||
files[] = quicktabs.module
|
||||
files[] = quicktabs.classes.inc
|
||||
files[] = includes/quicktabs_style_plugin.inc
|
||||
files[] = tests/quicktabs.test
|
||||
configure = admin/structure/quicktabs
|
||||
dependencies[] = "ctools"
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-03-29
|
||||
version = "7.x-3.4"
|
||||
core = "7.x"
|
||||
project = "quicktabs"
|
||||
datestamp = "1332980461"
|
||||
|
177
sites/all/modules/quicktabs/quicktabs.install
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the quicktabs module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function quicktabs_schema() {
|
||||
$schema['quicktabs'] = array(
|
||||
'description' => 'The quicktabs table.',
|
||||
'export' => array(
|
||||
'key' => 'machine_name',
|
||||
'identifier' => 'quicktabs',
|
||||
'default hook' => 'quicktabs_default_quicktabs',
|
||||
'api' => array(
|
||||
'owner' => 'quicktabs',
|
||||
'api' => 'quicktabs',
|
||||
'minimum_version' => 1,
|
||||
'current_version' => 1,
|
||||
),
|
||||
'export callback' => 'quicktabs_export',
|
||||
),
|
||||
'fields' => array(
|
||||
'machine_name' => array(
|
||||
'description' => 'The primary identifier for a qt block.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'ajax' => array(
|
||||
'description' => 'Whether this is an ajax views block.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'hide_empty_tabs' => array(
|
||||
'description' => 'Whether this tabset hides empty tabs.',
|
||||
'type' => 'int',
|
||||
'size' => 'tiny',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'default_tab' => array(
|
||||
'description' => 'Default tab.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'title' => array(
|
||||
'description' => 'The title of this quicktabs block.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'tabs' => array(
|
||||
'description' => 'A serialized array of the contents of this qt block.',
|
||||
'type' => 'text',
|
||||
'size' => 'medium',
|
||||
'not null' => TRUE,
|
||||
'serialize' => TRUE,
|
||||
),
|
||||
'renderer' => array(
|
||||
'description' => 'The rendering mechanism.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'style' => array(
|
||||
'description' => 'The tab style.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'options' => array(
|
||||
'description' => 'A serialized array of the options for this qt instance.',
|
||||
'type' => 'text',
|
||||
'size' => 'medium',
|
||||
'not null' => FALSE,
|
||||
'serialize' => TRUE,
|
||||
),
|
||||
),
|
||||
'primary key' => array('machine_name'),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update to 7.x-3.x
|
||||
*/
|
||||
function quicktabs_update_7300() {
|
||||
|
||||
if (!db_field_exists('quicktabs', 'machine_name')) {
|
||||
// Pull all existing quicktabs, and then delete existing quicktabs. We will reinsert.
|
||||
$result = db_query("SELECT * FROM {quicktabs}");
|
||||
if (!db_query("DELETE FROM {quicktabs}")) {
|
||||
throw new DrupalUpdateException(t('Could not complete the update.'));
|
||||
}
|
||||
|
||||
db_drop_field('quicktabs', 'qtid');
|
||||
$name_field = array(
|
||||
'description' => 'The primary identifier for a qt block.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
);
|
||||
db_add_field('quicktabs', 'machine_name', $name_field);
|
||||
db_add_primary_key('quicktabs', array('machine_name'));
|
||||
|
||||
$output = $used = array();
|
||||
foreach ($result as $qt) {
|
||||
$row = (array)$qt;
|
||||
// Generate a machine-readable string
|
||||
$qt_name = strtolower(preg_replace('/[^a-zA-Z0-9_]+/', '_', $row['title']));
|
||||
$i = 0;
|
||||
while (in_array($i == 0 ? $qt_name : "{$qt_name}_{$i}", $used)) {
|
||||
$i++;
|
||||
}
|
||||
$row['machine_name'] = $used[] = $i == 0 ? $qt_name : "{$qt_name}_{$i}";
|
||||
unset($row['qtid']);
|
||||
unset($row['style']);
|
||||
$row['renderer'] = 'tabs';
|
||||
$placeholders = implode(', ', array_keys($row));
|
||||
$values = array();
|
||||
// Ugh - really?? Somebody tell me there's a better way to do this :-/
|
||||
foreach ($row as $name => $value) {
|
||||
$values[':' . $name] = $value;
|
||||
}
|
||||
$tokens = implode(', ', array_keys($values));
|
||||
db_query("INSERT INTO {quicktabs} ($placeholders) VALUES($tokens)", $values);
|
||||
|
||||
$output[] = "Converted quicktab {$row['machine_name']}.";
|
||||
}
|
||||
}
|
||||
|
||||
// Add the renderer field
|
||||
$renderer_field = array(
|
||||
'description' => 'The rendering mechanism.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => 'quicktabs',
|
||||
);
|
||||
db_add_field('quicktabs', 'renderer', $renderer_field);
|
||||
$output[] = "Added the renderer field";
|
||||
|
||||
|
||||
return implode('<br />', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the options field which will hold renderer-specific options.
|
||||
*/
|
||||
function quicktabs_update_7301() {
|
||||
$options_field = array(
|
||||
'description' => 'A serialized array of the options for this qt instance.',
|
||||
'type' => 'text',
|
||||
'size' => 'medium',
|
||||
'not null' => FALSE,
|
||||
'serialize' => TRUE,
|
||||
);
|
||||
db_add_field('quicktabs', 'options', $options_field);
|
||||
return "Added the options field";
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the registry because of changed method name.
|
||||
*/
|
||||
function quicktabs_update_7302() {
|
||||
registry_rebuild();
|
||||
}
|
630
sites/all/modules/quicktabs/quicktabs.module
Normal file
@@ -0,0 +1,630 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function quicktabs_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#quicktabs':
|
||||
$output = '<p>' . t('The Quicktabs module allows you to create blocks of tabbed content. Clicking on the tabs makes the corresponding content display instantly (it uses jQuery). The content for each tabbed section can be a node, view, block or another Quicktabs instance. You can create an unlimited number of Quicktabs instances, each of which will automatically have an associated block.') . '</p>';
|
||||
$output .= '<p>' . t('The <a href="@quicktabs">quicktabs page</a> displays all quicktabs currently available on your site. Create new quicktabs using the <a href="@add-quicktab">add quicktab page</a> (the block containing a new quicktab must also be enabled on the <a href="@blocks">blocks administration page</a>).', array('@quicktabs' => url('admin/structure/quicktabs'), '@add-quicktab' => url('admin/structure/quicktab/add'), '@blocks' => url('admin/structure/block'))) . '</p>';
|
||||
return $output;
|
||||
}
|
||||
if ($path == 'admin/structure/quicktabs' && module_exists('block')) {
|
||||
return '<p>' . t('Each Quicktabs instance has a corresponding block that is managed on the <a href="@blocks">blocks administration page</a>.', array('@blocks' => url('admin/structure/block'))) . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function quicktabs_menu() {
|
||||
$items['admin/structure/quicktabs'] = array(
|
||||
'title' => 'Quicktabs',
|
||||
'description' => 'Create blocks of tabbed content.',
|
||||
'page callback' => 'quicktabs_list',
|
||||
'access callback' => 'user_access',
|
||||
'access arguments' => array('administer quicktabs'),
|
||||
'type' => MENU_NORMAL_ITEM,
|
||||
'file' => 'quicktabs.admin.inc',
|
||||
);
|
||||
$items['admin/structure/quicktabs/list'] = array(
|
||||
'title' => 'List quicktabs',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
);
|
||||
$items['admin/structure/quicktabs/add'] = array(
|
||||
'title' => 'Add Quicktabs Instance',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('quicktabs_form', 'add'),
|
||||
'access arguments' => array('administer quicktabs'),
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
'file' => 'quicktabs.admin.inc',
|
||||
);
|
||||
$items['admin/structure/quicktabs/manage/%quicktabs'] = array(
|
||||
'title' => 'Edit quicktab',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('quicktabs_form', 'edit', 4),
|
||||
'access arguments' => array('administer quicktabs'),
|
||||
'file' => 'quicktabs.admin.inc',
|
||||
);
|
||||
$items['admin/structure/quicktabs/manage/%quicktabs/edit'] = array(
|
||||
'title' => 'Edit quicktab',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'context' => MENU_CONTEXT_INLINE,
|
||||
);
|
||||
$items['admin/structure/quicktabs/manage/%quicktabs/delete'] = array(
|
||||
'title' => 'Delete quicktab',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('quicktabs_block_delete', 4),
|
||||
'access arguments' => array('administer quicktabs'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'quicktabs.admin.inc',
|
||||
);
|
||||
$items['admin/structure/quicktabs/manage/%quicktabs/clone'] = array(
|
||||
'title' => 'Clone quicktab',
|
||||
'page callback' => 'quicktabs_clone',
|
||||
'page arguments' => array(4),
|
||||
'access arguments' => array('administer quicktabs'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'quicktabs.admin.inc',
|
||||
);
|
||||
$items['admin/structure/quicktabs/manage/%quicktabs/export'] = array(
|
||||
'title' => 'Export',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('quicktabs_export_form', 4),
|
||||
'access arguments' => array('administer quicktabs'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'quicktabs.admin.inc',
|
||||
);
|
||||
$items['quicktabs/ajax'] = array(
|
||||
'page callback' => 'quicktabs_ajax',
|
||||
'access callback' => 'user_access',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_permission().
|
||||
*/
|
||||
function quicktabs_permission() {
|
||||
return array(
|
||||
'administer quicktabs' => array(
|
||||
'title' => t('Administer Quicktabs'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function quicktabs_theme() {
|
||||
return array(
|
||||
'quicktabs_admin_form_tabs' => array(
|
||||
'render element' => 'tabs',
|
||||
'file' => 'quicktabs.admin.inc',
|
||||
),
|
||||
'qt_ui_tabs' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
'qt_ui_tabs_tabset' => array(
|
||||
'render element' => 'tabset',
|
||||
),
|
||||
'qt_quicktabs' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
'qt_quicktabs_tabset' => array(
|
||||
'render element' => 'tabset',
|
||||
),
|
||||
'qt_accordion' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
'quicktabs_tab_access_denied' => array(
|
||||
'variables' => array('tab'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_info().
|
||||
*/
|
||||
function quicktabs_block_info() {
|
||||
$blocks = array();
|
||||
foreach (quicktabs_load_multiple() as $qt_name => $quicktabs) {
|
||||
$blocks[$qt_name]['info'] = $quicktabs->title;
|
||||
}
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_view().
|
||||
*/
|
||||
function quicktabs_block_view($delta = '') {
|
||||
$block = array();
|
||||
if ($qt = quicktabs_build_quicktabs($delta)) {
|
||||
if (isset($qt['content']) && !empty($qt['content'])) {
|
||||
$block['content'] = $qt['content'];
|
||||
$block['content']['#contextual_links']['quicktabs'] = array('admin/structure/quicktabs/manage', array($delta));
|
||||
$block['subject'] = check_plain($qt['#title']);
|
||||
}
|
||||
}
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Quicktabs instance.
|
||||
*
|
||||
* This function can be called by other modules to programmatically build a
|
||||
* quicktabs instance.
|
||||
*
|
||||
* @param name. The machine name of the Quicktabs instance to build - if a name
|
||||
* is passed that does not correspond to an existing instance, then it is taken
|
||||
* to be a completely custom instance and is built from only the custom tabs
|
||||
* that are passed in.
|
||||
*
|
||||
* @param settings. An array of settings that will override the options of the Quicktabs
|
||||
* instance from the database, or if no existing instance is being used, these
|
||||
* will override the default settings. Possible keys are 'style', 'hide_empty_tabs',
|
||||
* ajax', 'default_tab', 'renderer', 'title' and 'options'.
|
||||
*
|
||||
* @param custom_tabs. An array representing custom tab contents, which will be
|
||||
* appended to the Quicktabs instance from the database, or if no existing instance
|
||||
* is being used, the custom tabs will be the entire contents. An example custom_tabs
|
||||
* array would be array(array('title' => 'custom', 'contents' => array('#markup' =>
|
||||
* t('Some markup'), 'weight' => 5));
|
||||
*
|
||||
* @return A render array that can be used as block content in hook_block_view
|
||||
* (see quicktabs_block_view()), but can also just be added to the page array
|
||||
* during hook_page_alter, or output anywhere else where it's sure to get
|
||||
* passed through drupal_render().
|
||||
*/
|
||||
function quicktabs_build_quicktabs($name, $settings = array(), $custom_tabs = array()) {
|
||||
if ($info = quicktabs_load($name)) {
|
||||
// Allow other modules to alter the Quicktabs instance before it gets output.
|
||||
drupal_alter('quicktabs', $info);
|
||||
$info = (array) $info;
|
||||
$settings = array_merge($info, $settings);
|
||||
$contents = $settings['tabs'];
|
||||
unset($settings['tabs'], $settings['machine_name']);
|
||||
}
|
||||
elseif (!empty($custom_tabs)) {
|
||||
// We'll be creating a custom Quicktabs instance. Make sure we're using an
|
||||
// alphanumeric name.
|
||||
$name = preg_replace('/[^[a-zA-Z]_]/', '_', $name);
|
||||
$contents = array();
|
||||
}
|
||||
else {
|
||||
// If $name doesn't correspond to an existing Quicktabs instance, and there
|
||||
// are no custom tabs to render, then we have nothing to do.
|
||||
return array();
|
||||
}
|
||||
$renderer = isset($settings['renderer']) ? $settings['renderer'] : 'quicktabs';
|
||||
unset($settings['renderer']);
|
||||
foreach ($custom_tabs as &$tab) {
|
||||
$tab += array(
|
||||
'type' => 'prerendered',
|
||||
'weight' => 0,
|
||||
);
|
||||
}
|
||||
$contents = array_merge($custom_tabs, $contents);
|
||||
$weight = array();
|
||||
foreach ($contents as $key => $item) {
|
||||
// Load the plugin responsible for rendering this item, if it is not a
|
||||
// prerendered tab.
|
||||
if ($item['type'] != 'prerendered') {
|
||||
ctools_plugin_load_class('quicktabs', 'contents', $item['type'], 'handler');
|
||||
}
|
||||
|
||||
// Add item's weight to our weights array so that we can then sort by weight.
|
||||
$weight[$key] = $item['weight'];
|
||||
|
||||
// Make sure we're not going to try to load the same QuickSet instance
|
||||
// inside itself.
|
||||
if ($item['type'] == 'qtabs' && $item['machine_name'] == $name) {
|
||||
unset($contents[$key]);
|
||||
unset($weight[$key]);
|
||||
}
|
||||
}
|
||||
// Only sort by weight if the tabs haven't already been sorted by some other
|
||||
// mechanism, e.g. Views in the case of the Views style plugin.
|
||||
if (!isset($settings['sorted']) || !$settings['sorted']) {
|
||||
array_multisort($weight, SORT_ASC, $contents);
|
||||
}
|
||||
else {
|
||||
unset($settings['sorted']);
|
||||
}
|
||||
if ($qt = quickset_renderer_factory($name, $contents, $renderer, $settings)) {
|
||||
$renderable_qt = array('#title' => $qt->getTitle(), 'content' => $qt->render());
|
||||
return $renderable_qt;
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for tab content.
|
||||
*
|
||||
* @param name The machine name of the quicktabs instance.
|
||||
*
|
||||
* @param index The tab index we're returning content for.
|
||||
*
|
||||
* @param type The type of content we're rendering.
|
||||
*
|
||||
* @return a json-formatted ajax commands array.
|
||||
*/
|
||||
function quicktabs_ajax($name, $index, $type) {
|
||||
|
||||
$args = func_get_args();
|
||||
$variable_args = array_slice($args, 3);
|
||||
// Add the Quicktabs machine name to the args we pass to the content renderer
|
||||
array_unshift($variable_args, $name);
|
||||
|
||||
$data = QuickSet::ajaxRenderContent($type, $variable_args);
|
||||
|
||||
$commands = array();
|
||||
$tabpage_id = 'quicktabs-tabpage-'. $name .'-' . $index;
|
||||
$commands[] = ajax_command_append('#quicktabs-container-'. $name, '<div id="' . $tabpage_id .'" class="quicktabs-tabpage">'. $data .'</div>');
|
||||
$page = array('#type' => 'ajax', '#commands' => $commands);
|
||||
ajax_deliver($page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the quicktabs data for a particular instance.
|
||||
*/
|
||||
function quicktabs_load($name) {
|
||||
$qts = quicktabs_load_multiple(array($name));
|
||||
return isset($qts[$name]) ? $qts[$name] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the quicktabs data.
|
||||
*/
|
||||
function quicktabs_load_multiple($names = array()) {
|
||||
ctools_include('export');
|
||||
$defaults = empty($names) ? ctools_export_load_object('quicktabs', 'all') : ctools_export_load_object('quicktabs', 'names', $names);
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the specified Quicktabs instance with translatable strings.
|
||||
*/
|
||||
function quicktabs_export($qt, $indent = '') {
|
||||
$output = ctools_export_object('quicktabs', $qt, $indent);
|
||||
$translatables = array();
|
||||
if (!empty($qt->title)) {
|
||||
$translatables[] = $qt->title;
|
||||
}
|
||||
foreach ($qt->tabs as $tab) {
|
||||
$translatables[] = $tab['title'];
|
||||
}
|
||||
$translatables = array_filter(array_unique($translatables));
|
||||
if (!empty($translatables)) {
|
||||
$output .= "\n";
|
||||
$output .= "{$indent}// Translatables\n";
|
||||
$output .= "{$indent}// Included for use with string extractors like potx.\n";
|
||||
sort($translatables);
|
||||
foreach ($translatables as $string) {
|
||||
$output .= "{$indent}t(" . ctools_var_export($string) . ");\n";
|
||||
}
|
||||
$output .= "\n";
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_string_info()
|
||||
*/
|
||||
function quicktabs_i18n_string_info() {
|
||||
$groups['quicktabs'] = array(
|
||||
'title' => t('Quicktabs'),
|
||||
'description' => t('Vocabulary titles and term names for localizable quicktabs.'),
|
||||
'format' => FALSE, // This group doesn't have strings with format
|
||||
'list' => TRUE, // This group can list all strings
|
||||
);
|
||||
return $groups;
|
||||
}
|
||||
|
||||
function quicktabs_translate($name, $string, $langcode = NULL, $textgroup = 'quicktabs') {
|
||||
return function_exists('i18n_string') ? i18n_string($textgroup . ':' . $name, $string, array('langcode' => $langcode)) : $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update translatable strings.
|
||||
*/
|
||||
function quicktabs_i18n_update_strings($names = array()) {
|
||||
if (!function_exists('i18n_string_update')) return;
|
||||
$qts = quicktabs_load_multiple($names);
|
||||
foreach ($qts as $name => $quicktabs) {
|
||||
i18n_string_update("quicktabs:title:$name", $quicktabs->title);
|
||||
foreach ($quicktabs->tabs as $tabkey => $tab) {
|
||||
i18n_string_update("quicktabs:tab:$name-$tabkey:title", $tab['title']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_string_refresh().
|
||||
*
|
||||
* Refresh translations for all user-generated strings managed by quicktabs.
|
||||
* This will load all strings inputted via the quicktabs user interface and
|
||||
* register them (and their translations, if there are any) with the
|
||||
* i18n_strings system.
|
||||
*/
|
||||
function quicktabs_i18n_string_refresh($group) {
|
||||
if ($group === 'quicktabs') {
|
||||
quicktabs_i18n_update_strings();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ctools_plugin_type().
|
||||
*/
|
||||
function quicktabs_ctools_plugin_type() {
|
||||
return array(
|
||||
// Renderer plugins control the display of sets of items, e.g. as tabs.
|
||||
'renderers' => array(
|
||||
'cache' => TRUE,
|
||||
'use hooks' => TRUE,
|
||||
'classes' => array('handler'),
|
||||
),
|
||||
// Content plugins control the display of individual items.
|
||||
'contents' => array(
|
||||
'cache' => TRUE,
|
||||
'use hooks' => TRUE,
|
||||
'classes' => array('handler'),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_quicktabs_renderers().
|
||||
*/
|
||||
function quicktabs_quicktabs_renderers() {
|
||||
$info = array();
|
||||
$path = drupal_get_path('module', 'quicktabs') . '/plugins';
|
||||
$info['quicktabs'] = array(
|
||||
'path' => $path,
|
||||
'handler' => array(
|
||||
'file' => 'QuickQuicktabs.inc',
|
||||
'class' => 'QuickQuicktabs',
|
||||
),
|
||||
);
|
||||
$info['ui_tabs'] = array(
|
||||
'path' => $path,
|
||||
'handler' => array(
|
||||
'file' => 'QuickUiTabs.inc',
|
||||
'class' => 'QuickUitabs',
|
||||
),
|
||||
);
|
||||
$info['accordion'] = array(
|
||||
'path' => $path,
|
||||
'handler' => array(
|
||||
'file' => 'QuickAccordion.inc',
|
||||
'class' => 'QuickAccordion',
|
||||
),
|
||||
);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_quicktabs_contents().
|
||||
*/
|
||||
function quicktabs_quicktabs_contents() {
|
||||
$info = array();
|
||||
$path = drupal_get_path('module', 'quicktabs') . '/plugins';
|
||||
$info['block'] = array(
|
||||
'path' => $path,
|
||||
'handler' => array(
|
||||
'file' => 'QuickBlockContent.inc',
|
||||
'class' => 'QuickBlockContent',
|
||||
),
|
||||
'dependencies' => array('block'),
|
||||
);
|
||||
$info['view'] = array(
|
||||
'path' => $path,
|
||||
'handler' => array(
|
||||
'file' => 'QuickViewContent.inc',
|
||||
'class' => 'QuickViewContent',
|
||||
),
|
||||
'dependencies' => array('views'),
|
||||
);
|
||||
$info['node'] = array(
|
||||
'path' => $path,
|
||||
'handler' => array(
|
||||
'file' => 'QuickNodeContent.inc',
|
||||
'class' => 'QuickNodeContent',
|
||||
),
|
||||
);
|
||||
$info['qtabs'] = array(
|
||||
'path' => $path,
|
||||
'handler' => array(
|
||||
'file' => 'QuickQtabsContent.inc',
|
||||
'class' => 'QuickQtabsContent',
|
||||
),
|
||||
);
|
||||
$info['callback'] = array(
|
||||
'path' => $path,
|
||||
'handler' => array(
|
||||
'file' => 'QuickCallbackContent.inc',
|
||||
'class' => 'QuickCallbackContent',
|
||||
),
|
||||
);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a renderered QuickSet.
|
||||
*/
|
||||
function quickset_renderer_factory($name, $contents, $renderer, $settings) {
|
||||
return QuickSet::QuickSetRendererFactory($name, $contents, $renderer, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object that implements the QuickContent interface.
|
||||
*/
|
||||
function quick_content_factory($name, $item) {
|
||||
return QuickContent::factory($name, $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the machine name is in use.
|
||||
*/
|
||||
function quicktabs_machine_name_exists($machine_name) {
|
||||
$qt_exists = db_query_range('SELECT 1 FROM {quicktabs} WHERE machine_name = :name', 0, 1, array(':name' => $machine_name))->fetchField();
|
||||
return $qt_exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_views_api().
|
||||
*/
|
||||
function quicktabs_views_api() {
|
||||
return array(
|
||||
'api' => 3,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function to display the access denied tab.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_quicktabs_tab_access_denied($variables) {
|
||||
return t('You are not authorized to access this content.');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetch the necessary CSS files for the tab style.
|
||||
*/
|
||||
function quicktabs_get_css($style) {
|
||||
if ($style == 'default') {
|
||||
// Get the default style.
|
||||
$style = variable_get('quicktabs_tabstyle', 'nostyle');
|
||||
}
|
||||
if ($style == 'nostyle') return array();
|
||||
$style_css = _quicktabs_get_style_css($style);
|
||||
return $style_css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the css file for given style.
|
||||
*/
|
||||
function _quicktabs_get_style_css($style) {
|
||||
$tabstyles = &drupal_static(__FUNCTION__);
|
||||
if (empty($tabstyles)) {
|
||||
$cid = 'quicktabs_tabstyles';
|
||||
$cache = cache_get($cid);
|
||||
if (!$cache) {
|
||||
$tabstyles = module_invoke_all('quicktabs_tabstyles');
|
||||
cache_set($cid, $tabstyles);
|
||||
}
|
||||
else {
|
||||
$tabstyles = $cache->data;
|
||||
}
|
||||
}
|
||||
if ($css_file = array_search($style, $tabstyles)) {
|
||||
return array('data' => $css_file);
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function to output tablinks for jQuery UI style tabs.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_qt_ui_tabs_tabset($vars) {
|
||||
|
||||
$output = '<ul>';
|
||||
foreach ($vars['tabset']['tablinks'] as $i => $tab) {
|
||||
if (is_array($tab)) {
|
||||
$output .= '<li>'. drupal_render($tab) .'</li>';
|
||||
}
|
||||
}
|
||||
$output .= '</ul>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function to output content for jQuery UI style tabs.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_qt_ui_tabs($variables) {
|
||||
$element = $variables['element'];
|
||||
$output = '<div '. drupal_attributes($element['#options']['attributes']) .'>';
|
||||
$output .= drupal_render($element['tabs']);
|
||||
|
||||
if (isset($element['active'])) {
|
||||
$output .= drupal_render($element['active']);
|
||||
}
|
||||
else {
|
||||
foreach ($element['divs'] as $div) {
|
||||
$output .= drupal_render($div);
|
||||
}
|
||||
}
|
||||
|
||||
$output .= '</div>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function to output tablinks for classic Quicktabs style tabs.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_qt_quicktabs_tabset($vars) {
|
||||
$variables = array(
|
||||
'attributes' => array(
|
||||
'class' => 'quicktabs-tabs quicktabs-style-' . $vars['tabset']['#options']['style'],
|
||||
),
|
||||
'items' => array(),
|
||||
);
|
||||
foreach (element_children($vars['tabset']['tablinks']) as $key) {
|
||||
$item = array();
|
||||
if (is_array($vars['tabset']['tablinks'][$key])) {
|
||||
$tab = $vars['tabset']['tablinks'][$key];
|
||||
if ($key == $vars['tabset']['#options']['active']) {
|
||||
$item['class'] = array('active');
|
||||
}
|
||||
$item['data'] = drupal_render($tab);
|
||||
$variables['items'][] = $item;
|
||||
}
|
||||
}
|
||||
return theme('item_list', $variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function to output content for classic Quicktabs style tabs.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_qt_quicktabs($variables) {
|
||||
$element = $variables['element'];
|
||||
$output = '<div '. drupal_attributes($element['#options']['attributes']) .'>';
|
||||
$output .= drupal_render($element['tabs']);
|
||||
|
||||
$output .= drupal_render($element['container']);
|
||||
|
||||
$output .= '</div>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Theme function to output markup for the accordion style.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_qt_accordion($variables) {
|
||||
$element = $variables['element'];
|
||||
$output = '<div '. drupal_attributes($element['#options']['attributes']) .'>';
|
||||
foreach ($element['divs'] as $div) {
|
||||
$output .= drupal_render($div);
|
||||
}
|
||||
|
||||
$output .= '</div>';
|
||||
return $output;
|
||||
}
|
28
sites/all/modules/quicktabs/quicktabs.views.inc
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
// Id:$
|
||||
|
||||
/**
|
||||
* @file Add Views module hooks to Quicktabs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_views_plugins().
|
||||
*/
|
||||
function quicktabs_views_plugins() {
|
||||
$path = drupal_get_path('module', 'quicktabs');
|
||||
|
||||
return array(
|
||||
'style' => array(
|
||||
'quicktabs' => array(
|
||||
'title' => t('Quicktabs'),
|
||||
'help' => t('Display view in Quicktabs.'),
|
||||
'handler' => 'quicktabs_style_plugin',
|
||||
'path' => "$path/includes",
|
||||
'theme' => 'quicktabs_view',
|
||||
'uses row plugin' => TRUE,
|
||||
'uses options' => TRUE,
|
||||
'type' => 'normal',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/* QT style selection form */
|
||||
|
||||
div.quicktabs-preview {
|
||||
border: none;
|
||||
width: 250px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
#quicktabs-styles .quicktabs-tabstyles .form-item {
|
||||
width: 280px;
|
||||
float: left;
|
||||
margin: 0 10px 10px 0;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
}
|
||||
#quicktabs-styles .quicktabs-tabstyles .form-item .option {
|
||||
display: block;
|
||||
background-color: #bfe3ff;
|
||||
font: bold 12px/18px verdana;
|
||||
color: #0a5793;
|
||||
}
|
||||
#quicktabs-styles .quicktabs-tabstyles .form-item .option:hover {
|
||||
background-color: #aadaff;
|
||||
cursor: pointer;
|
||||
color: #003863;
|
||||
}
|
||||
#quicktabs-styles .quicktabs-tabstyles .form-item .option .form-radio {
|
||||
margin-right: 5px;
|
||||
float: left;
|
||||
height: 15px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
#quicktabs-styles .quicktabs_wrapper {
|
||||
margin: 5px;
|
||||
font: bold 12px/170% Verdana;
|
||||
}
|
||||
|
@@ -0,0 +1,11 @@
|
||||
name = Quicktabs Styles
|
||||
description = Adds predefined tab styles to choose from per Quicktabs instance.
|
||||
core = 7.x
|
||||
configure=admin/structure/quicktabs/styles
|
||||
dependencies[] = "quicktabs"
|
||||
; Information added by drupal.org packaging script on 2012-03-29
|
||||
version = "7.x-3.4"
|
||||
core = "7.x"
|
||||
project = "quicktabs"
|
||||
datestamp = "1332980461"
|
||||
|
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function quicktabs_tabstyles_theme() {
|
||||
return array(
|
||||
'quicktabs_style_options' => array(
|
||||
'render element' => 'quicktabs_tabstyle',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function quicktabs_tabstyles_menu() {
|
||||
$items['admin/structure/quicktabs/styles'] = array(
|
||||
'title' => 'Styles',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('quicktabs_tabstyles_styles'),
|
||||
'access arguments' => array('administer quicktabs'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for admin/structure/quicktabs/styles. The style chooser form.
|
||||
*/
|
||||
function quicktabs_tabstyles_styles() {
|
||||
$options = array();
|
||||
$styles = module_invoke_all('quicktabs_tabstyles');
|
||||
// The keys used for options must be valid html id-s.
|
||||
// Removing the css file path, because that can't be used.
|
||||
foreach ($styles as $style) {
|
||||
$options[$style] = $style;
|
||||
}
|
||||
ksort($options);
|
||||
|
||||
$form['quicktabs_tabstyle'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Quicktab styles'),
|
||||
'#options' => array('nostyle' => t('No style')) + $options,
|
||||
'#default_value' => variable_get('quicktabs_tabstyle', 'nostyle'),
|
||||
'#description' => t('Select the default style for quicktabs.'),
|
||||
'#attributes' => array('class' => array('quicktabs-tabstyles', 'clear-block')),
|
||||
'#theme' => 'quicktabs_style_options',
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for QuickTabs styles.
|
||||
*/
|
||||
function quicktabs_tabstyles_styles_submit($form, &$form_state) {
|
||||
variable_set('quicktabs_tabstyle', $form_state['values']['quicktabs_tabstyle']);
|
||||
drupal_set_message(t('The default quicktab style has been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function for quicktabs style radio options.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_quicktabs_style_options($variables) {
|
||||
$style_element = $variables['quicktabs_tabstyle'];
|
||||
$markup = '';
|
||||
|
||||
$tabs = array(
|
||||
array('title' => t('One'), 'contents' => array('#markup' => t('First tab')), 'weight' => 0),
|
||||
array('title' => t('Two'), 'contents' => array('#markup' => t('Second tab')), 'weight' => 1),
|
||||
array('title' => t('Three'), 'contents' => array('#markup' => t('Third tab')), 'weight' => 2)
|
||||
);
|
||||
|
||||
$options = array('renderer' => 'quicktabs', 'hide_empty_tabs' => 0, 'ajax' => 0);
|
||||
// Preview for each style.
|
||||
foreach (element_children($style_element) as $style) {
|
||||
$element = $style_element[$style];
|
||||
$options['style'] = $style;
|
||||
$quicktabs = quicktabs_build_quicktabs(drupal_strtolower($style), $options, $tabs);
|
||||
$preview = '<div class="quicktabs-preview">'. drupal_render($quicktabs['content']) .'</div>';
|
||||
$element['#description'] = t('%style preview', array('%style' => $element['#title'])) .':<br />'. $preview;
|
||||
$markup .= drupal_render($element);
|
||||
}
|
||||
$build = array(
|
||||
'style' => array('#markup' => $markup),
|
||||
'#attached' => array('css' => array(drupal_get_path('module', 'quicktabs_tabstyles') . '/css/quicktabs-tabstyles-admin.css')),
|
||||
);
|
||||
return drupal_render($build);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_quicktabs_tabstyles().
|
||||
*/
|
||||
function quicktabs_tabstyles_quicktabs_tabstyles() {
|
||||
$tabstyles_directory = drupal_get_path('module', 'quicktabs_tabstyles') . '/tabstyles';
|
||||
$files = file_scan_directory($tabstyles_directory, '/\.css$/');
|
||||
$tabstyles = array();
|
||||
foreach ($files as $file) {
|
||||
// Skip RTL files.
|
||||
if (!strpos($file->name, '-rtl')) {
|
||||
$tabstyles[$file->uri] = drupal_ucfirst($file->name);
|
||||
}
|
||||
}
|
||||
return $tabstyles;
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-arrows{
|
||||
padding:0 0 0 10px!important;
|
||||
height:25px;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-arrows li{
|
||||
float:right;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
|
||||
.quicktabs_main.quicktabs-style-arrows{
|
||||
clear:both;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-arrows{
|
||||
font:bold 12px/170% Verdana;
|
||||
border-bottom:1px solid #ccc;
|
||||
padding:0 10px 0 0!important;
|
||||
line-height:22px;
|
||||
margin:0 0 10px 0;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-arrows a{
|
||||
text-decoration:none;
|
||||
background:transparent url(images/arrows.gif) no-repeat center 17px;
|
||||
padding:2px 10px 4px;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-arrows li.active a,
|
||||
ul.quicktabs-tabs.quicktabs-style-arrows li a:hover{
|
||||
text-decoration:none;
|
||||
background:transparent url(images/arrows.gif) no-repeat center bottom;
|
||||
}
|
After Width: | Height: | Size: 77 B |
@@ -0,0 +1,12 @@
|
||||
|
||||
.quicktabs_main.quicktabs-style-basic{
|
||||
border:1px solid #aaa;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-basic{
|
||||
border-bottom:none;
|
||||
padding:0 0 0 5px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-basic li{
|
||||
float:right;
|
||||
margin:0 0 0 3px;
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
|
||||
.quicktabs_main.quicktabs-style-basic{
|
||||
background-color:#fff;
|
||||
border:1px solid #aaa;
|
||||
border-top:none;
|
||||
padding:10px;
|
||||
clear:both;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-basic{
|
||||
border-bottom:1px solid #aaa;
|
||||
padding:0 5px 0 0;
|
||||
font:bold 12px/19px Verdana !important;
|
||||
font-weight:bold;
|
||||
height:19px;
|
||||
margin:0;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-basic a{
|
||||
font:bold 12px/19px Verdana !important;
|
||||
text-decoration:none;
|
||||
color:#aaa;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-basic a:hover{
|
||||
color:#555;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-basic li{
|
||||
border:1px solid #e5e5e5;
|
||||
border-bottom:none;
|
||||
padding:2px 5px;
|
||||
margin:0 3px 0 0;
|
||||
position:relative;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-basic li:hover{
|
||||
border:1px solid #ccc;
|
||||
border-bottom:none;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-basic li.active{
|
||||
border:1px solid #aaa;
|
||||
border-bottom:1px solid #fff;
|
||||
background-color:#fff;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-basic li.active a{
|
||||
color:#027AC6;
|
||||
}
|
@@ -0,0 +1,4 @@
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-bullets li{
|
||||
float: right;
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
|
||||
.quicktabs_main.quicktabs-style-bullets{
|
||||
clear:both;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-bullets{
|
||||
margin:0 0 10px 0;
|
||||
font-size:11px;
|
||||
list-style: none;
|
||||
padding:3px 0 23px 0;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-bullets li{
|
||||
float: left;
|
||||
height:20px;
|
||||
margin:0 5px;
|
||||
padding: 0 0 0 10px;
|
||||
background:transparent url(images/bullets.png) no-repeat 0 -80px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-bullets li a{
|
||||
font:bold 12px/170% Verdana;
|
||||
margin: 0;
|
||||
display:block;
|
||||
padding:0px 17px 0px 7px;
|
||||
text-decoration:none;
|
||||
color: #777 !important;
|
||||
background:transparent url(images/bullets.png) no-repeat right -100px ;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-bullets li:hover a{
|
||||
background-position: right -60px ;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-bullets li:hover{
|
||||
background-position: 0 -40px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-bullets li.active a,
|
||||
ul.quicktabs-tabs.quicktabs-style-bullets li.active a:hover{
|
||||
color: #0372d9 !important;
|
||||
background-position:right -20px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-bullets li.active{
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
/* IE6 Gif (no PNGs) */
|
||||
|
||||
*html ul.quicktabs-tabs.quicktabs-style-bullets li a{
|
||||
background:transparent url(images/bullets.gif) no-repeat right -100px ;
|
||||
}
|
||||
*html ul.quicktabs-tabs.quicktabs-style-bullets li{ /* image for IE6 */
|
||||
background:transparent url(images/bullets.gif) no-repeat 0 -80px;
|
||||
}
|
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,38 @@
|
||||
|
||||
/* RTL support */
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li {
|
||||
float: right;
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li a {
|
||||
padding: 4px 12px 0px 22px;
|
||||
background: transparent url(images/tab-right-sep-rtl.png) no-repeat left -38px;
|
||||
}
|
||||
|
||||
/*override active tab*/
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.active {
|
||||
background: transparent url(images/tab-left-sep-rtl.png) no-repeat right 0;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.active a {
|
||||
background: transparent url(images/tab-right-sep-rtl.png) no-repeat left 0;
|
||||
}
|
||||
|
||||
/*override first (most right) tab*/
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.first {
|
||||
background: transparent url(images/tab-left-rtl.png) no-repeat right -38px;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.first.active {
|
||||
background: transparent url(images/tab-left-rtl.png) no-repeat right 0px;
|
||||
}
|
||||
|
||||
/*override last (most left) tab*/
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.last a {
|
||||
background: transparent url(images/tab-right-rtl.png) no-repeat left -38px;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.last.active a {
|
||||
background:transparent url(images/tab-right-rtl.png) no-repeat left 0px;
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
|
||||
/* Excel style tabs */
|
||||
|
||||
.quicktabs_main.quicktabs-style-excel {
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
padding: 10px 5px 2px;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel {
|
||||
margin: 0;
|
||||
padding: 0 15px;
|
||||
font-size: 1em;
|
||||
list-style: none;
|
||||
height: 24px;
|
||||
background: transparent url(images/tab-bar.png) repeat-x left bottom;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li {
|
||||
float: left;
|
||||
margin: 0 -5px -5px -5px;
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li a {
|
||||
font: bold 12px/170% Verdana;
|
||||
font-size-adjust: none;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 4px 22px 0px 12px;
|
||||
border-width: 0;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
background: transparent url(images/tab-right-sep.png) no-repeat right -38px;
|
||||
}
|
||||
|
||||
/*override hover*/
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li:hover {
|
||||
/*background: transparent url(images/tab-left-sep.png) no-repeat left -76px;*/
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li a:hover {
|
||||
color: #000;
|
||||
/*background: transparent url(images/tab-right-sep.png) no-repeat right -76px;*/
|
||||
}
|
||||
|
||||
/*override active tab*/
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.active {
|
||||
background: transparent url(images/tab-left-sep.png) no-repeat left 0;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.active a {
|
||||
background: transparent url(images/tab-right-sep.png) no-repeat right 0;
|
||||
}
|
||||
|
||||
/*override first tab*/
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.first {
|
||||
background: transparent url(images/tab-left.png) no-repeat left -38px;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.first:hover {
|
||||
/*background: transparent url(images/tab-left.png) no-repeat left -76px;*/
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.first.active {
|
||||
background: transparent url(images/tab-left.png) no-repeat left 0px;
|
||||
}
|
||||
|
||||
/*override last tab*/
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.last a {
|
||||
background: transparent url(images/tab-right.png) no-repeat right -38px;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.last a:hover {
|
||||
/*background: transparent url(images/tab-right.png) no-repeat right -76px;*/
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-excel li.last.active a {
|
||||
background:transparent url(images/tab-right.png) no-repeat right 0px;
|
||||
}
|
After Width: | Height: | Size: 160 B |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,9 @@
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-garland li {
|
||||
float: right;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-garland li a:link,
|
||||
ul.quicktabs-tabs.quicktabs-style-garland li a:visited {
|
||||
padding: 8px 11px 4px 12px;
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
|
||||
.quicktabs_main.quicktabs-style-garland {
|
||||
clear:both;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-garland {
|
||||
background: #bcd6eb url('images/bg.gif') repeat-x bottom;
|
||||
font:bold 12px/20px Verdana;
|
||||
padding: 3px 0px 3px;
|
||||
height: 20px;
|
||||
margin:0 0 10px 0;
|
||||
}
|
||||
|
||||
.sidebar ul.quicktabs-tabs.quicktabs-style-garland {
|
||||
padding:0 0 3px 0;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-garland li {
|
||||
margin:0;
|
||||
padding:0;
|
||||
display: block;
|
||||
float: left;
|
||||
padding: 2px 0 1px !important;
|
||||
list-style-type: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.sidebar ul.quicktabs-tabs.quicktabs-style-garland li {
|
||||
margin:0;
|
||||
display: block;
|
||||
float: left;
|
||||
padding: 2px 0 1px;
|
||||
list-style-type: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-garland li a:link,
|
||||
ul.quicktabs-tabs.quicktabs-style-garland li a:visited {
|
||||
color: #fff;
|
||||
padding: 8px 12px 4px 11px;
|
||||
margin:0;
|
||||
font:bold 12px/20px Verdana;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-garland li.active a {
|
||||
color: #027AC6 !important;
|
||||
background: url('images/tab-right.gif') no-repeat right bottom;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-garland li.active {
|
||||
background: url('images/tab-left.gif') no-repeat left bottom;
|
||||
}
|
||||
|
||||
.sidebar ul.quicktabs-tabs.quicktabs-style-garland li.active a {
|
||||
color: #027AC6 !important;
|
||||
background: url('images/tab-right-sidebar.gif') no-repeat right bottom;
|
||||
}
|
||||
.sidebar ul.quicktabs-tabs.quicktabs-style-garland li.active {
|
||||
background: url('images/tab-left-sidebar.gif') no-repeat left bottom;
|
||||
}
|
||||
|
||||
/* IE 6 Debug */
|
||||
* html ul.quicktabs-tabs.quicktabs-style-garland,
|
||||
* html .sidebar ul.quicktabs-tabs.quicktabs-style-garland {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
/* IE 7 Debug */
|
||||
*+html .sidebar ul.quicktabs-tabs.quicktabs-style-garland li a:link {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
After Width: | Height: | Size: 99 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 580 B |
After Width: | Height: | Size: 563 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 6.4 KiB |
@@ -0,0 +1,4 @@
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-mac li{
|
||||
float: right;
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
|
||||
.quicktabs_main.quicktabs-style-mac{
|
||||
clear:both;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-mac{
|
||||
margin:0 0 10px 0;
|
||||
font-size:11px;
|
||||
list-style: none;
|
||||
padding:3px 0 23px 0;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-mac li{
|
||||
float: left;
|
||||
height:24px;
|
||||
margin:0 5px;
|
||||
padding: 0 0 0 15px;
|
||||
background:transparent url(images/mac.png) no-repeat 0 0px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-mac li a{
|
||||
font:bold 12px/170% Verdana;
|
||||
margin: 0;
|
||||
display:block;
|
||||
padding:0px 15px 5px 0px;
|
||||
font-weight:bold;
|
||||
text-decoration:none;
|
||||
color: #fff;
|
||||
background:transparent url(images/mac.png) no-repeat right -25px ;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-mac li:hover a{
|
||||
background-position: right -75px ;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-mac li:hover{
|
||||
background-position: 0 -50px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-mac li.active a,
|
||||
ul.quicktabs-tabs.quicktabs-style-mac li.active a:hover{
|
||||
background-position:right -125px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-mac li.active{
|
||||
background-position: 0 -100px;
|
||||
}
|
||||
|
||||
/* IE6 Gif (no PNGs) */
|
||||
|
||||
*html ul.quicktabs-tabs.quicktabs-style-mac li a{
|
||||
color:#fff!important;
|
||||
background:transparent url(images/mac.gif) no-repeat right -25px ;
|
||||
}
|
||||
*html ul.quicktabs-tabs.quicktabs-style-mac li{ /* image for IE6 */
|
||||
background:transparent url(images/mac.gif) no-repeat 0 0px;
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
|
||||
.quicktabs_wrapper.quicktabs-style-navlist {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-navlist {
|
||||
float: left;
|
||||
padding: 4px 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: 20%;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-navlist li {
|
||||
display: block;
|
||||
margin-right: -1px;
|
||||
padding: 0;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-navlist li a {
|
||||
display: block;
|
||||
color: #404040;
|
||||
text-align: right;
|
||||
text-decoration: none;
|
||||
margin: 0;
|
||||
padding: 0 10px 0 0;
|
||||
height: 23px;
|
||||
font-weight: normal;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-navlist li.active {
|
||||
background: #F0F8FC;
|
||||
border-top: 1px solid #BFD0FF;
|
||||
border-bottom: 1px solid #BFD0FF;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-navlist li.active a {
|
||||
color: #007734;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.quicktabs_main.quicktabs-style-navlist {
|
||||
float: left;
|
||||
border: 1px solid #BFD0FF;
|
||||
background: #F0F8FC;
|
||||
padding: 10px;
|
||||
min-height: 64px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 70%;
|
||||
}
|
After Width: | Height: | Size: 858 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 51 B |
After Width: | Height: | Size: 120 B |
@@ -0,0 +1,4 @@
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-phylactere li{
|
||||
float: right;
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
|
||||
.quicktabs_main.quicktabs-style-phylactere{
|
||||
clear:both;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-phylactere{
|
||||
margin:0 0 10px 0;
|
||||
padding:0;
|
||||
font-size:12px;
|
||||
list-style: none;
|
||||
background:transparent url(images/shade.png) repeat-x bottom left;
|
||||
height:28px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-phylactere li{
|
||||
float: left;
|
||||
margin:0 5px;
|
||||
padding:0 0 8px 23px;
|
||||
background:transparent url(images/phy.png) no-repeat 0 -59px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-phylactere li a{
|
||||
font:bold 12px/170% Verdana;
|
||||
margin: 0;
|
||||
display:block;
|
||||
padding:2px 21px 1px 0;
|
||||
text-decoration:none;
|
||||
color: #bbb !important;
|
||||
background:transparent url(images/phy.png) no-repeat right -35px ;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-phylactere li a:hover{
|
||||
text-decoration:none;
|
||||
color:#888 !important;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-phylactere li.active a{
|
||||
color: #0372d9 !important;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-phylactere li.active{
|
||||
background-position: 0 0;
|
||||
padding-bottom:11px;
|
||||
position:relative;
|
||||
top:-2px;
|
||||
}
|
||||
|
||||
/* IE6 */
|
||||
|
||||
*html ul.quicktabs-tabs.quicktabs-style-phylactere{
|
||||
background: transparent url(images/shade.gif) repeat-x 0 25px;
|
||||
}
|
||||
*html ul.quicktabs-tabs.quicktabs-style-phylactere li a{
|
||||
padding:0px 21px 3px 0;
|
||||
background-image: url(images/phy.gif);
|
||||
}
|
||||
*html ul.quicktabs-tabs.quicktabs-style-phylactere li{ /* image for IE6 */
|
||||
background-image: url(images/phy.gif);
|
||||
}
|
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 216 B |
After Width: | Height: | Size: 221 B |
@@ -0,0 +1,9 @@
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li {
|
||||
float: right;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li a,
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li a:visited {
|
||||
float: right;
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
|
||||
/* Quicktabs - Sky theme style
|
||||
* http://drupal.org/project/sky
|
||||
*/
|
||||
|
||||
.quicktabs_main.quicktabs-style-sky {
|
||||
border: 1px solid #eee;
|
||||
clear: both;
|
||||
padding: 10px 5px 0 5px;
|
||||
position: relative;
|
||||
top: -0.1em;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li {
|
||||
float: left;
|
||||
font-weight: normal;
|
||||
list-style: none;
|
||||
margin: 0.3em 0 0 0;
|
||||
height: 2.65em;
|
||||
min-height: 2.95em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li.active {
|
||||
margin: -0.2em 0 0 0;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li a,
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li a:visited {
|
||||
float: left;
|
||||
display: block;
|
||||
height: 2.65em;
|
||||
min-height: 2.95em;
|
||||
line-height: 2.95em;
|
||||
padding: 0 8px;
|
||||
text-decoration: none;
|
||||
border-right: 1px solid #eee;
|
||||
border-top: 1px solid #eee;
|
||||
font-size: .95em;
|
||||
background: #fff url('images/bg-shade-light.png') repeat-x bottom left;
|
||||
color: #777;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li a:hover,
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li.active a:hover {
|
||||
text-decoration: none;
|
||||
border-color: #B3B3B3;
|
||||
background: #B3B3B3 url('images/bg-shade-medium.png') repeat-x bottom left;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li.active a,
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li.active a:visited {
|
||||
height: 3.05em;
|
||||
min-height: 3.35em;
|
||||
line-height: 3.35em;
|
||||
font-weight: normal;
|
||||
border: 1px solid #eee;
|
||||
background: #858585 url('images/bg-shade-dark.png') repeat-x bottom left;
|
||||
border-color: #555;
|
||||
color: #fff;
|
||||
font-size: .95em;
|
||||
font-weight: normal;
|
||||
top: -0.025em;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li:first-child a {
|
||||
border-left: solid 1px #eee;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li.active a {
|
||||
border-left: solid 1px #777;
|
||||
}
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li a:focus,
|
||||
ul.quicktabs-tabs.quicktabs-style-sky li a:active {
|
||||
outline: none;
|
||||
|
||||
}
|
||||
|
||||
/* Opera */
|
||||
@media all and (min-width: 0px) {
|
||||
body .quicktabs_main.quicktabs-style-sky {
|
||||
top: -0.2em;
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 160 B |
After Width: | Height: | Size: 331 B |
After Width: | Height: | Size: 473 B |
@@ -0,0 +1,6 @@
|
||||
|
||||
/* RTL support */
|
||||
|
||||
ul.quicktabs-tabs.quicktabs-style-zen li{
|
||||
float: right;
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
|
||||
/**
|
||||
* Style from the new (great!) ZEN THEME for Drupal
|
||||
* http://drupal.org/project/zen
|
||||
*/
|
||||
|
||||
.quicktabs_main.quicktabs-style-zen{
|
||||
clear:both;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-zen{
|
||||
margin:0 0 10px 0;
|
||||
padding:0 0 3px;
|
||||
font-size:1em;
|
||||
list-style: none;
|
||||
height:21px;
|
||||
background:transparent url(images/tab-bar.png) repeat-x left bottom;
|
||||
}
|
||||
*html ul.quicktabs-tabs.quicktabs-style-zen li{
|
||||
margin-bottom:-5px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-zen li{
|
||||
float: left;
|
||||
margin:0 5px;
|
||||
padding: 0 0 0 5px;
|
||||
background:transparent url(images/tab-left-ie6.png) no-repeat left -38px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-zen li a{
|
||||
font:bold 12px/170% Verdana;
|
||||
font-size-adjust:none;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding:4px 17px 0px 12px;
|
||||
border-width: 0;
|
||||
font-weight:bold;
|
||||
text-decoration:none;
|
||||
background: transparent url(images/tab-right-ie6.png) no-repeat right -38px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-zen li:hover a{
|
||||
border-width: 0;
|
||||
background:transparent url(images/tab-right-ie6.png) no-repeat right -76px;
|
||||
}
|
||||
quicktabs-tabs.quicktabs-style-zen li:hover{
|
||||
background:transparent url(images/tab-left-ie6.png) no-repeat left -76px;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-zen li.active a,
|
||||
ul.quicktabs-tabs.quicktabs-style-zen li.active a:hover{
|
||||
text-decoration:none;
|
||||
border-width: 0;
|
||||
background:transparent url(images/tab-right-ie6.png) no-repeat right 0;
|
||||
}
|
||||
ul.quicktabs-tabs.quicktabs-style-zen li.active{
|
||||
background:transparent url(images/tab-left-ie6.png) no-repeat left 0;
|
||||
}
|
134
sites/all/modules/quicktabs/tests/quicktabs.test
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
class QuicktabsAdminTestCase extends DrupalWebTestCase {
|
||||
|
||||
/**
|
||||
* Implementation of getInfo().
|
||||
*/
|
||||
function getInfo() {
|
||||
return array(
|
||||
'name' => t('Quicktabs tests'),
|
||||
'description' => t('Add, edit and delete quicktabs.'),
|
||||
'group' => t('Quicktabs'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp('ctools','quicktabs');
|
||||
|
||||
// Create and login user
|
||||
$admin_user = $this->drupalCreateUser(array('access administration pages', 'administer quicktabs', 'administer nodes'));
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create some nodes that we can populate our tabs with.
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$node = new stdClass();
|
||||
$node->type = 'page';
|
||||
$node->title = 'This is node number '. ($i+1);
|
||||
$node->body[LANGUAGE_NONE][0]['value'] = $this->randomString(255);
|
||||
node_object_prepare($node);
|
||||
node_save($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Quicktabs instance through the UI and ensure that it is saved properly.
|
||||
*/
|
||||
function testQuicktabsAdmin() {
|
||||
// Add a new Quicktabs instance using the UI.
|
||||
$edit = array(
|
||||
'machine_name' => strtolower($this->randomName()),
|
||||
'title' => $this->randomName(),
|
||||
'ajax' => 0,
|
||||
'hide_empty_tabs' => FALSE,
|
||||
'renderer' => 'quicktabs',
|
||||
);
|
||||
|
||||
$saved = $edit;
|
||||
// We'll be using the $saved array to compare against the Quicktabs instance
|
||||
// that gets created. However, hierarchical form elements are dealt with
|
||||
// differenly so we can't include them in the $saved array like this.
|
||||
$tab_title_first = $this->randomName();
|
||||
$tab_title_second = $this->randomName();
|
||||
$edit += array(
|
||||
'tabs[0][type]' => 'node',
|
||||
'tabs[0][node][nid]' => 1,
|
||||
'tabs[0][title]' => $tab_title_first,
|
||||
'tabs[0][weight]' => 0,
|
||||
'tabs[1][type]' => 'node',
|
||||
'tabs[1][node][nid]' => 2,
|
||||
'tabs[1][title]' => $tab_title_second,
|
||||
'tabs[1][weight]' => 1,
|
||||
);
|
||||
// Now add on the tabs info to the $saved array - it's the same as what we
|
||||
// put in the edit form but we need it in proper array format.
|
||||
$saved['tabs'] = array(0 => array('type' => 'node', 'nid' => 1, 'title' => $tab_title_first, 'weight' => 0), 1 => array('type' => 'node', 'nid' => 2, 'title' => $tab_title_second, 'weight' => 1));
|
||||
$this->drupalPost('admin/structure/quicktabs/add', $edit, t('Save'));
|
||||
|
||||
// Check that the quicktabs object is in the database.
|
||||
$quicktabs = quicktabs_load($edit['machine_name']);
|
||||
$this->assertTrue($quicktabs != FALSE, t('Quicktabs instance found in database'));
|
||||
|
||||
// Check each individual property of the quicktabs and make sure it was set.
|
||||
foreach ($saved as $property => $value) {
|
||||
if ($property == 'tabs') {
|
||||
// Add some extra default values that we didn't include on the form, for
|
||||
// the sake of comparing the two tabs arrays.
|
||||
foreach ($value as &$val) {
|
||||
$val += array('teaser' => 0, 'hide_title' => 1);
|
||||
}
|
||||
}
|
||||
$this->assertEqual($quicktabs->$property, $value, t('Quicktabs property %property properly saved.', array('%property' => $property)));
|
||||
}
|
||||
|
||||
// Edit the Quicktabs instance through the UI.
|
||||
$edit = array(
|
||||
'title' => $this->randomName(),
|
||||
'ajax' => 1,
|
||||
'hide_empty_tabs' => TRUE,
|
||||
'renderer' => 'ui_tabs',
|
||||
'default_tab' => 1,
|
||||
);
|
||||
|
||||
$saved = $edit;
|
||||
$tab_title_first = $this->randomName();
|
||||
$tab_title_second = $this->randomName();
|
||||
$edit += array(
|
||||
'tabs[0][title]' => $tab_title_first,
|
||||
'tabs[0][weight]' => 1,
|
||||
'tabs[0][node][nid]' => 3,
|
||||
'tabs[0][node][teaser]' => 1,
|
||||
'tabs[0][node][hide_title]' => FALSE,
|
||||
'tabs[1][title]' => $tab_title_second,
|
||||
'tabs[1][weight]' => 0,
|
||||
'tabs[1][node][nid]' => 4,
|
||||
'tabs[1][node][teaser]' => FALSE,
|
||||
'tabs[1][node][hide_title]' => 1,
|
||||
);
|
||||
$saved['tabs'] = array(0 => array('type' => 'node', 'nid' => 4, 'title' => $tab_title_second, 'weight' => 0, 'teaser' => 0, 'hide_title' => 1), 1 => array('type' => 'node', 'nid' => 3, 'title' => $tab_title_first, 'weight' => 1, 'teaser' => 1, 'hide_title' => 0));
|
||||
$this->drupalPost('admin/structure/quicktabs/manage/'. $quicktabs->machine_name .'/edit', $edit, t('Save'));
|
||||
|
||||
// Reset static vars because ctools will have cached the original $quicktabs object
|
||||
drupal_static_reset();
|
||||
// Check that the quicktabs object is in the database.
|
||||
$edited_qt = quicktabs_load($quicktabs->machine_name);
|
||||
$this->assertTrue($edited_qt != FALSE, t('Quicktabs instance found in database'));
|
||||
|
||||
// Check each individual property of the quicktabs and make sure it was set.
|
||||
foreach ($saved as $property => $value) {
|
||||
$this->assertEqual($edited_qt->$property, $value, t('Quicktabs property %property properly saved.', array('%property' => $property)));
|
||||
}
|
||||
|
||||
// Delete the Quicktabs instance through the UI.
|
||||
$this->drupalPost('admin/structure/quicktabs/manage/'. $quicktabs->machine_name .'/delete', array(), t('Delete'));
|
||||
// Reset static vars because ctools will have cached the original $quicktabs object
|
||||
drupal_static_reset();
|
||||
// Check that the quicktabs object is no longer in the database.
|
||||
$this->assertNull(quicktabs_load($quicktabs->machine_name), t('Quicktabs instance not found in database'));
|
||||
}
|
||||
|
||||
}
|
||||
|