update 2.2 + precedent custom commits

Signed-off-by: bachy <git@g-u-i.net>
This commit is contained in:
bachy 2012-10-27 15:06:38 +02:00
parent aff5ecb650
commit 7884444ec6
38 changed files with 1759 additions and 590 deletions

View File

@ -1,6 +1,25 @@
Wysiwyg 7.x-2.x, xxxx-xx-xx Wysiwyg 7.x-2.x, xxxx-xx-xx
--------------------------- ---------------------------
#1388224 by ksenzee, sun, TwoD: Fixed editors detaching on form submissions.
#682160 by n_vashenko, TwoD: Fixed lists plugin support for TinyMCE.
#1414354 by Merco: Fixed none.js breaks if textarea.js is not loaded.
#1064600 by TwoD: Fixed maximized editors hidden under Drupal's toolbar.
#1405786 by logaritmisk: Fixed CKEditor being wider than parent elements.
#1531896 by Chi: Fixed strict warning for WYMeditor.
#1442226 by robertom: Fixed inverted list button names for WYMeditor.
#1352426 by TwoD, sun: Added install notes (CKEditor edition clarification).
#1112212 by timdiacon, TwoD: Added language direction buttons for CKEditor.
#1398560 by markwittens: Fixed TinyMCE removing the longdesc attribute.
#970452 by smk-ka, sun, TwoD, drzraf: Fixed outdated TinyMCE plugin info.
#1155678 by james.elliott, Jody Lynn, sun: Add Drupal.detachBehaviors support.
#624018 by smk-ka, quartsize, dagmar, nedjo, rickvug, catch, sun: Added Features support.
#1238766 by Dave Reid: Fixed Missing cells in profile plugins table.
#1073106 by scottrouse: Fixed 'Input Format' should be 'Text Format'.
#1153458 by TwoD: Fixed TinyMCE 'Verify HTML' setting ignored.
#1125582 by TwoD: Fixed TinyMCE fullscreen plugin deletes content.
#1078834 by sun: Fixed coding standards errors.
#1173476 by jim0203, sun: Fixed installation instructions in README.txt.
Wysiwyg 7.x-2.1, 2011-06-19 Wysiwyg 7.x-2.1, 2011-06-19

View File

@ -1,274 +1,339 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
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.
Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Preamble
Cambridge, MA 02139, 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.
The licenses for most software are designed to take away your freedom to When we speak of free software, we are referring to freedom, not
share and change it. By contrast, the GNU General Public License is price. Our General Public Licenses are designed to make sure that you
intended to guarantee your freedom to share and change free software--to have the freedom to distribute copies of free software (and charge for
make sure the software is free for all its users. This General Public License this service if you wish), that you receive source code or can get it
applies to most of the Free Software Foundation's software and to any other if you want it, that you can change the software or use pieces of it
program whose authors commit to using it. (Some other Free Software in new free programs; and that you know you can do these things.
Foundation software is covered by the GNU Library 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 To protect your rights, we need to make restrictions that forbid
General Public Licenses are designed to make sure that you have the anyone to deny you these rights or to ask you to surrender the rights.
freedom to distribute copies of free software (and charge for this service if These restrictions translate to certain responsibilities for you if you
you wish), that you receive source code or can get it if you want it, that you distribute copies of the software, or if you modify it.
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 For example, if you distribute copies of such a program, whether
deny you these rights or to ask you to surrender the rights. These restrictions gratis or for a fee, you must give the recipients all the rights that
translate to certain responsibilities for you if you distribute copies of the you have. You must make sure that they, too, receive or can get the
software, or if you modify it. source code. And you must show them these terms so they know their
rights.
For example, if you distribute copies of such a program, whether gratis or for We protect your rights with two steps: (1) copyright the software, and
a fee, you must give the recipients all the rights that you have. You must make (2) offer you this license which gives you legal permission to copy,
sure that they, too, receive or can get the source code. And you must show distribute and/or modify the software.
them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) Also, for each author's protection and ours, we want to make certain
offer you this license which gives you legal permission to copy, distribute that everyone understands that there is no warranty for this free
and/or modify the software. 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.
Also, for each author's protection and ours, we want to make certain that Finally, any free program is threatened constantly by software
everyone understands that there is no warranty for this free software. If the patents. We wish to avoid the danger that redistributors of a free
software is modified by someone else and passed on, we want its recipients program will individually obtain patent licenses, in effect making the
to know that what they have is not the original, so that any problems program proprietary. To prevent this, we have made it clear that any
introduced by others will not reflect on the original authors' reputations. patent must be licensed for everyone's free use or not licensed at all.
Finally, any free program is threatened constantly by software patents. We The precise terms and conditions for copying, distribution and
wish to avoid the danger that redistributors of a free program will individually modification follow.
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 GNU GENERAL PUBLIC LICENSE
follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
GNU GENERAL PUBLIC LICENSE 0. This License applies to any program or other work which contains
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND a notice placed by the copyright holder saying it may be distributed
MODIFICATION 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".
0. This License applies to any program or other work which contains a notice Activities other than copying, distribution and modification are not
placed by the copyright holder saying it may be distributed under the terms covered by this License; they are outside its scope. The act of
of this General Public License. The "Program", below, refers to any such running the Program is not restricted, and the output from the Program
program or work, and a "work based on the Program" means either the is covered only if its contents constitute a work based on the
Program or any derivative work under copyright law: that is to say, a work Program (independent of having been made by running the Program).
containing the Program or a portion of it, either verbatim or with Whether that is true depends on what the Program does.
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 1. You may copy and distribute verbatim copies of the Program's
by this License; they are outside its scope. The act of running the Program is source code as you receive it, in any medium, provided that you
not restricted, and the output from the Program is covered only if its contents conspicuously and appropriately publish on each copy an appropriate
constitute a work based on the Program (independent of having been made copyright notice and disclaimer of warranty; keep intact all the
by running the Program). Whether that is true depends on what the Program notices that refer to this License and to the absence of any warranty;
does. and give any other recipients of the Program a copy of this License
along with the Program.
1. You may copy and distribute verbatim copies of the Program's source You may charge a fee for the physical act of transferring a copy, and
code as you receive it, in any medium, provided that you conspicuously and you may at your option offer warranty protection in exchange for a fee.
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 2. You may modify your copy or copies of the Program or any portion
may at your option offer warranty protection in exchange for a fee. 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:
2. You may modify your copy or copies of the Program or any portion of it, a) You must cause the modified files to carry prominent notices
thus forming a work based on the Program, and copy and distribute such stating that you changed the files and the date of any change.
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 b) You must cause any work that you distribute or publish, that in
you changed the files and the date of any change. 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.
b) You must cause any work that you distribute or publish, that in whole or in c) If the modified program normally reads commands interactively
part contains or is derived from the Program or any part thereof, to be when run, you must cause it, when started running for such
licensed as a whole at no charge to all third parties under the terms of this interactive use in the most ordinary way, to print or display an
License. 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.)
c) If the modified program normally reads commands interactively when run, These requirements apply to the modified work as a whole. If
you must cause it, when started running for such interactive use in the most identifiable sections of that work are not derived from the Program,
ordinary way, to print or display an announcement including an appropriate and can be reasonably considered independent and separate works in
copyright notice and a notice that there is no warranty (or else, saying that themselves, then this License, and its terms, do not apply to those
you provide a warranty) and that users may redistribute the program under sections when you distribute them as separate works. But when you
these conditions, and telling the user how to view a copy of this License. distribute the same sections as part of a whole which is a work based
(Exception: if the Program itself is interactive but does not normally print such on the Program, the distribution of the whole must be on the terms of
an announcement, your work based on the Program is not required to print this License, whose permissions for other licensees extend to the
an announcement.) entire whole, and thus to each and every part regardless of who wrote it.
These requirements apply to the modified work as a whole. If identifiable Thus, it is not the intent of this section to claim rights or contest
sections of that work are not derived from the Program, and can be your rights to work written entirely by you; rather, the intent is to
reasonably considered independent and separate works in themselves, then exercise the right to control the distribution of derivative or
this License, and its terms, do not apply to those sections when you distribute collective works based on the Program.
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 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 with the Program (or with a work based on the Program) on a volume of
storage or distribution medium does not bring the other work under the scope a storage or distribution medium does not bring the other work under
of this License. the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under 3. You may copy and distribute the Program (or a work based on it,
Section 2) in object code or executable form under the terms of Sections 1 under Section 2) in object code or executable form under the terms of
and 2 above provided that you also do one of the following: Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source a) Accompany it with the complete corresponding machine-readable
code, which must be distributed under the terms of Sections 1 and 2 above source code, which must be distributed under the terms of Sections
on a medium customarily used for software interchange; or, 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 b) Accompany it with a written offer, valid for at least three
any third party, for a charge no more than your cost of physically performing years, to give any third party, for a charge no more than your
source distribution, a complete machine-readable copy of the corresponding cost of physically performing source distribution, a complete
source code, to be distributed under the terms of Sections 1 and 2 above on machine-readable copy of the corresponding source code, to be
a medium customarily used for software interchange; or, 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 c) Accompany it with the information you received as to the offer
corresponding source code. (This alternative is allowed only for to distribute corresponding source code. (This alternative is
noncommercial distribution and only if you received the program in object allowed only for noncommercial distribution and only if you
code or executable form with such an offer, in accord with Subsection b received the program in object code or executable form with such
above.) an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for 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 making modifications to it. For an executable work, complete source
means all the source code for all modules it contains, plus any associated code means all the source code for all modules it contains, plus any
interface definition files, plus the scripts used to control compilation and associated interface definition files, plus the scripts used to
installation of the executable. However, as a special exception, the source control compilation and installation of the executable. However, as a
code distributed need not include anything that is normally distributed (in special exception, the source code distributed need not include
either source or binary form) with the major components (compiler, kernel, anything that is normally distributed (in either source or binary
and so on) of the operating system on which the executable runs, unless that form) with the major components (compiler, kernel, and so on) of the
component itself accompanies the executable. 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 If distribution of executable or object code is made by offering
copy from a designated place, then offering equivalent access to copy the access to copy from a designated place, then offering equivalent
source code from the same place counts as distribution of the source code, access to copy the source code from the same place counts as
even though third parties are not compelled to copy the source along with the distribution of the source code, even though third parties are not
object code. compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as 4. You may not copy, modify, sublicense, or distribute the Program
expressly provided under this License. Any attempt otherwise to copy, except as expressly provided under this License. Any attempt
modify, sublicense or distribute the Program is void, and will automatically otherwise to copy, modify, sublicense or distribute the Program is
terminate your rights under this License. However, parties who have received void, and will automatically terminate your rights under this License.
copies, or rights, from you under this License will not have their licenses However, parties who have received copies, or rights, from you under
terminated so long as such parties remain in full compliance. 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. 5. You are not required to accept this License, since you have not
However, nothing else grants you permission to modify or distribute the signed it. However, nothing else grants you permission to modify or
Program or its derivative works. These actions are prohibited by law if you distribute the Program or its derivative works. These actions are
do not accept this License. Therefore, by modifying or distributing the prohibited by law if you do not accept this License. Therefore, by
Program (or any work based on the Program), you indicate your acceptance modifying or distributing the Program (or any work based on the
of this License to do so, and all its terms and conditions for copying, Program), you indicate your acceptance of this License to do so, and
distributing or modifying the Program or works based on it. 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 6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original Program), the recipient automatically receives a license from the
licensor to copy, distribute or modify the Program subject to these terms and original licensor to copy, distribute or modify the Program subject to
conditions. You may not impose any further restrictions on the recipients' these terms and conditions. You may not impose any further
exercise of the rights granted herein. You are not responsible for enforcing restrictions on the recipients' exercise of the rights granted herein.
compliance by third parties to this License. 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 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 infringement or for any other reason (not limited to patent issues),
are imposed on you (whether by court order, agreement or otherwise) that conditions are imposed on you (whether by court order, agreement or
contradict the conditions of this License, they do not excuse you from the otherwise) that contradict the conditions of this License, they do not
conditions of this License. If you cannot distribute so as to satisfy excuse you from the conditions of this License. If you cannot
simultaneously your obligations under this License and any other pertinent distribute so as to satisfy simultaneously your obligations under this
obligations, then as a consequence you may not distribute the Program at all. License and any other pertinent obligations, then as a consequence you
For example, if a patent license would not permit royalty-free redistribution may not distribute the Program at all. For example, if a patent
of the Program by all those who receive copies directly or indirectly through license would not permit royalty-free redistribution of the Program by
you, then the only way you could satisfy both it and this License would be to 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. refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any If any portion of this section is held invalid or unenforceable under
particular circumstance, the balance of the section is intended to apply and any particular circumstance, the balance of the section is intended to
the section as a whole is intended to apply in other circumstances. 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 It is not the purpose of this section to induce you to infringe any
other property right claims or to contest validity of any such claims; this patents or other property right claims or to contest validity of any
section has the sole purpose of protecting the integrity of the free software such claims; this section has the sole purpose of protecting the
distribution system, which is implemented by public license practices. Many integrity of the free software distribution system, which is
people have made generous contributions to the wide range of software implemented by public license practices. Many people have made
distributed through that system in reliance on consistent application of that generous contributions to the wide range of software distributed
system; it is up to the author/donor to decide if he or she is willing to through that system in reliance on consistent application of that
distribute software through any other system and a licensee cannot impose system; it is up to the author/donor to decide if he or she is willing
that choice. 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 This section is intended to make thoroughly clear what is believed to
consequence of the rest of this License. be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain 8. If the distribution and/or use of the Program is restricted in
countries either by patents or by copyrighted interfaces, the original copyright certain countries either by patents or by copyrighted interfaces, the
holder who places the Program under this License may add an explicit original copyright holder who places the Program under this License
geographical distribution limitation excluding those countries, so that may add an explicit geographical distribution limitation excluding
distribution is permitted only in or among countries not thus excluded. In such those countries, so that distribution is permitted only in or among
case, this License incorporates the limitation as if written in the body of this countries not thus excluded. In such case, this License incorporates
License. the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions 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 of the General Public License from time to time. Such new versions will
similar in spirit to the present version, but may differ in detail to address new be similar in spirit to the present version, but may differ in detail to
problems or concerns. address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies Each version is given a distinguishing version number. If the Program
a version number of this License which applies to it and "any later version", specifies a version number of this License which applies to it and "any
you have the option of following the terms and conditions either of that later version", you have the option of following the terms and conditions
version or of any later version published by the Free Software Foundation. If either of that version or of any later version published by the Free
the Program does not specify a version number of this License, you may Software Foundation. If the Program does not specify a version number of
choose any version ever published by the Free Software Foundation. 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 10. If you wish to incorporate parts of the Program into other free
whose distribution conditions are different, write to the author to ask for programs whose distribution conditions are different, write to the author
permission. For software which is copyrighted by the Free Software to ask for permission. For software which is copyrighted by the Free
Foundation, write to the Free Software Foundation; we sometimes make Software Foundation, write to the Free Software Foundation; we sometimes
exceptions for this. Our decision will be guided by the two goals of make exceptions for this. Our decision will be guided by the two goals
preserving the free status of all derivatives of our free software and of of preserving the free status of all derivatives of our free software and
promoting the sharing and reuse of software generally. of promoting the sharing and reuse of software generally.
NO WARRANTY NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND REPAIR OR CORRECTION.
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 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
ARISING OUT OF THE USE OR INABILITY TO USE THE YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
OR DATA BEING RENDERED INACCURATE OR LOSSES POSSIBILITY OF SUCH DAMAGES.
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 END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -18,7 +18,8 @@ To submit bug reports and feature suggestions, or to track changes:
-- INSTALLATION -- -- INSTALLATION --
* Install as usual, see http://drupal.org/node/70151 for further information. * Install as usual, see
http://drupal.org/documentation/install/modules-themes/modules-7
* Go to Administration » Configuration » Content authoring » Wysiwyg, * Go to Administration » Configuration » Content authoring » Wysiwyg,
and follow the displayed installation instructions to download and install one and follow the displayed installation instructions to download and install one

View File

@ -27,8 +27,11 @@ function wysiwyg_ckeditor_editor() {
), ),
), ),
), ),
'install note callback' => 'wysiwyg_ckeditor_install_note',
'version callback' => 'wysiwyg_ckeditor_version', 'version callback' => 'wysiwyg_ckeditor_version',
'themes callback' => 'wysiwyg_ckeditor_themes', 'themes callback' => 'wysiwyg_ckeditor_themes',
'settings form callback' => 'wysiwyg_ckeditor_settings_form',
'init callback' => 'wysiwyg_ckeditor_init',
'settings callback' => 'wysiwyg_ckeditor_settings', 'settings callback' => 'wysiwyg_ckeditor_settings',
'plugin callback' => 'wysiwyg_ckeditor_plugins', 'plugin callback' => 'wysiwyg_ckeditor_plugins',
'plugin settings callback' => 'wysiwyg_ckeditor_plugin_settings', 'plugin settings callback' => 'wysiwyg_ckeditor_plugin_settings',
@ -48,6 +51,13 @@ function wysiwyg_ckeditor_editor() {
return $editor; return $editor;
} }
/**
* Return an install note.
*/
function wysiwyg_ckeditor_install_note() {
return '<p class="warning">' . t('Do NOT download the "CKEditor for Drupal" edition.') . '</p>';
}
/** /**
* Detect editor version. * Detect editor version.
* *
@ -111,6 +121,69 @@ function wysiwyg_ckeditor_themes($editor, $profile) {
} }
} }
/**
* Enhances the editor profile settings form for CKEditor.
*
* Adds support for CKEditor's advanced stylesSets, which are a more advanced
* implementation and combination of block formats and font styles that allow
* to adjust the HTML element, attributes, and CSS styles at once.
*
* @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Styles
* @see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html#.stylesSet
*/
function wysiwyg_ckeditor_settings_form(&$form, &$form_state) {
if (version_compare($form_state['wysiwyg']['editor']['installed version'], '3.2.1', '>=')) {
// Replace CSS classes element description to explain the advanced syntax.
$form['css']['css_classes']['#description'] = t('Optionally define CSS classes for the "Font style" dropdown list.<br />Enter one class on each line in the format: !format. Example: !example<br />If left blank, CSS classes are automatically imported from loaded stylesheet(s).', array(
'!format' => '<code>[label]=[element].[class]</code>',
'!example' => '<code>Title=h1.title</code>',
));
$form['css']['css_classes']['#element_validate'][] = 'wysiwyg_ckeditor_settings_form_validate_css_classes';
}
else {
// Versions below 3.2.1 do not support Font styles at all.
$form['css']['css_classes']['#access'] = FALSE;
}
}
/**
* #element_validate handler for CSS classes element altered by wysiwyg_ckeditor_settings_form().
*/
function wysiwyg_ckeditor_settings_form_validate_css_classes($element, &$form_state) {
if (wysiwyg_ckeditor_settings_parse_styles($element['#value']) === FALSE) {
form_error($element, t('The specified CSS classes are syntactically incorrect.'));
}
}
/**
* Returns an initialization JavaScript for this editor library.
*
* @param array $editor
* The editor library definition.
* @param string $library
* The library variant key from $editor['libraries'].
* @param object $profile
* The (first) wysiwyg editor profile.
*
* @return string
* A string containing inline JavaScript to execute before the editor library
* script is loaded.
*/
function wysiwyg_ckeditor_init($editor) {
// CKEditor unconditionally searches for its library filename in SCRIPT tags
// on the page upon loading the library in order to determine the base path to
// itself. When JavaScript aggregation is enabled, this search fails and all
// relative constructed paths within CKEditor are broken. The library has a
// CKEditor.basePath property, but it is not publicly documented and thus not
// reliable. The official documentation suggests to solve the issue through
// the global window variable.
// @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Specifying_the_Editor_Path
$library_path = base_path() . $editor['library path'] . '/';
return <<<EOL
window.CKEDITOR_BASEPATH = '$library_path';
EOL;
}
/** /**
* Return runtime editor settings for a given wysiwyg profile. * Return runtime editor settings for a given wysiwyg profile.
* *
@ -127,8 +200,7 @@ function wysiwyg_ckeditor_themes($editor, $profile) {
*/ */
function wysiwyg_ckeditor_settings($editor, $config, $theme) { function wysiwyg_ckeditor_settings($editor, $config, $theme) {
$settings = array( $settings = array(
'baseHref' => $GLOBALS['base_url'] . '/', 'width' => 'auto',
'width' => '100%',
// For better compatibility with smaller textareas. // For better compatibility with smaller textareas.
'resize_minWidth' => 450, 'resize_minWidth' => 450,
'height' => 420, 'height' => 420,
@ -167,7 +239,7 @@ function wysiwyg_ckeditor_settings($editor, $config, $theme) {
$settings['contentsCss'] = reset(wysiwyg_get_css()); $settings['contentsCss'] = reset(wysiwyg_get_css());
} }
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) { elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['contentsCss'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); $settings['contentsCss'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
} }
} }
else { else {
@ -175,16 +247,25 @@ function wysiwyg_ckeditor_settings($editor, $config, $theme) {
$settings['contentsCss'] = wysiwyg_get_css(); $settings['contentsCss'] = wysiwyg_get_css();
} }
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) { elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['contentsCss'] = explode(',', strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme()))); $settings['contentsCss'] = explode(',', strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL)))));
} }
} }
} }
// Parse and define the styles set for the Styles plugin (3.2.1+).
// @todo This should be a plugin setting, but Wysiwyg does not support
// plugin-specific settings yet.
if (!empty($config['buttons']['default']['Styles']) && version_compare($editor['installed version'], '3.2.1', '>=')) {
if ($styles = wysiwyg_ckeditor_settings_parse_styles($config['css_classes'])) {
$settings['stylesSet'] = $styles;
}
}
if (isset($config['language'])) { if (isset($config['language'])) {
$settings['language'] = $config['language']; $settings['language'] = $config['language'];
} }
if (isset($config['resizing'])) { if (isset($config['resizing'])) {
// CKEditor tests "!== false", so ensure it is a Boolean. // CKEditor performs a type-agnostic comparison on this particular setting.
$settings['resize_enabled'] = (bool) $config['resizing']; $settings['resize_enabled'] = (bool) $config['resizing'];
} }
if (isset($config['toolbar_loc'])) { if (isset($config['toolbar_loc'])) {
@ -240,6 +321,51 @@ function wysiwyg_ckeditor_settings($editor, $config, $theme) {
return $settings; return $settings;
} }
/**
* Parses CSS classes settings string into a stylesSet JavaScript settings array.
*
* @param string $css_classes
* A string containing CSS class definitions to add to the Style dropdown
* list, separated by newlines.
*
* @return array|false
* An array containing the parsed stylesSet definition, or FALSE on parse
* error.
*
* @see wysiwyg_ckeditor_settings_form()
* @see wysiwyg_ckeditor_settings_form_validate_css_classes()
*
* @todo This should be a plugin setting, but Wysiwyg does not support
* plugin-specific settings yet.
*/
function wysiwyg_ckeditor_settings_parse_styles($css_classes) {
$set = array();
$input = trim($css_classes);
if (empty($input)) {
return $set;
}
// Handle both Unix and Windows line-endings.
foreach (explode("\n", str_replace("\r", '', $input)) as $line) {
$line = trim($line);
// [label]=[element].[class][.[class]][...] pattern expected.
if (!preg_match('@^.+= *[a-zA-Z0-9]+(\.[a-zA-Z0-9_ -]+)*$@', $line)) {
return FALSE;
}
list($label, $selector) = explode('=', $line, 2);
$classes = explode('.', $selector);
$element = array_shift($classes);
$style = array();
$style['name'] = trim($label);
$style['element'] = trim($element);
if (!empty($classes)) {
$style['attributes']['class'] = implode(' ', array_map('trim', $classes));
}
$set[] = $style;
}
return $set;
}
/** /**
* Build a JS settings array of native external plugins that need to be loaded separately. * Build a JS settings array of native external plugins that need to be loaded separately.
*/ */
@ -294,6 +420,7 @@ function wysiwyg_ckeditor_plugins($editor) {
'Bold' => t('Bold'), 'Italic' => t('Italic'), 'Underline' => t('Underline'), 'Bold' => t('Bold'), 'Italic' => t('Italic'), 'Underline' => t('Underline'),
'Strike' => t('Strike-through'), 'Strike' => t('Strike-through'),
'JustifyLeft' => t('Align left'), 'JustifyCenter' => t('Align center'), 'JustifyRight' => t('Align right'), 'JustifyBlock' => t('Justify'), 'JustifyLeft' => t('Align left'), 'JustifyCenter' => t('Align center'), 'JustifyRight' => t('Align right'), 'JustifyBlock' => t('Justify'),
'BidiLtr' => t('Left-to-right'), 'BidiRtl' => t('Right-to-left'),
'BulletedList' => t('Bullet list'), 'NumberedList' => t('Numbered list'), 'BulletedList' => t('Bullet list'), 'NumberedList' => t('Numbered list'),
'Outdent' => t('Outdent'), 'Indent' => t('Indent'), 'Outdent' => t('Outdent'), 'Indent' => t('Indent'),
'Undo' => t('Undo'), 'Redo' => t('Redo'), 'Undo' => t('Undo'), 'Redo' => t('Redo'),
@ -325,6 +452,10 @@ function wysiwyg_ckeditor_plugins($editor) {
if (version_compare($editor['installed version'], '3.1.0.4885', '<')) { if (version_compare($editor['installed version'], '3.1.0.4885', '<')) {
unset($plugins['default']['buttons']['CreateDiv']); unset($plugins['default']['buttons']['CreateDiv']);
} }
if (version_compare($editor['installed version'], '3.4.0.5808', '<')) {
unset($plugins['default']['buttons']['BidiLtr']);
unset($plugins['default']['buttons']['BidiRtl']);
}
if (version_compare($editor['installed version'], '3.5.0.6260', '<')) { if (version_compare($editor['installed version'], '3.5.0.6260', '<')) {
unset($plugins['default']['buttons']['Iframe']); unset($plugins['default']['buttons']['Iframe']);
} }

102
editors/epiceditor.inc Normal file
View File

@ -0,0 +1,102 @@
<?php
/**
* @file
* Editor integration functions for EpicEditor.
*/
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_epiceditor_editor() {
$editor['epiceditor'] = array(
'title' => 'EpicEditor',
'vendor url' => 'http://oscargodson.github.com/EpicEditor',
'download url' => 'http://oscargodson.github.com/EpicEditor/docs/downloads/EpicEditor-v0.1.1.zip',
'libraries' => array(
'' => array(
'title' => 'Minified',
'files' => array('js/epiceditor.min.js'),
),
'src' => array(
'title' => 'Source',
'files' => array('js/epiceditor.js'),
),
),
'version callback' => 'wysiwyg_epiceditor_version',
'themes callback' => 'wysiwyg_epiceditor_themes',
'settings callback' => 'wysiwyg_epiceditor_settings',
'versions' => array(
'0.1.1' => array(
'js files' => array('epiceditor.js'),
),
),
);
return $editor;
}
/**
* Detect editor version.
*
* @param $editor
* An array containing editor properties as returned from hook_editor().
*
* @return
* The installed editor version.
*/
function wysiwyg_epiceditor_version($editor) {
$library = $editor['library path'] . '/js/epiceditor.js';
if (!file_exists($library)) {
return;
}
// @todo Do not load the entire file; use fgets() instead.
$library = file_get_contents($library, 'r');
$version = preg_match('%EpicEditor\.version = \'(.*)\'\;%', $library, $matches);
if (!isset($matches[1])) {
return;
}
return $matches[1];
}
/**
* Determine available editor themes or check/reset a given one.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $profile
* A wysiwyg editor profile.
*
* @return
* An array of theme names. The first returned name should be the default
* theme name.
*/
function wysiwyg_epiceditor_themes($editor, $profile) {
return array('epic-dark', 'epic-light');
// @todo Use the preview themes somewhere.
//return array('preview-dark', 'github');
}
/**
* Return runtime editor settings for a given wysiwyg profile.
*
* @param $editor
* A processed hook_editor() array of editor properties.
* @param $config
* An array containing wysiwyg editor profile settings.
* @param $theme
* The name of a theme/GUI/skin to use.
*
* @return
* A settings array to be populated in
* Drupal.settings.wysiwyg.configs.{editor}
*/
function wysiwyg_epiceditor_settings($editor, $config, $theme) {
$settings = array(
'basePath' => base_path() . $editor['library path'],
'clientSideStorage' => FALSE,
'theme' => $theme,
//'preview_theme' => '',
);
return $settings;
}

View File

@ -131,8 +131,8 @@ function wysiwyg_fckeditor_settings($editor, $config, $theme) {
if ($config['css_setting'] == 'theme') { if ($config['css_setting'] == 'theme') {
$settings['EditorAreaCSS'] = implode(',', wysiwyg_get_css()); $settings['EditorAreaCSS'] = implode(',', wysiwyg_get_css());
} }
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['EditorAreaCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); $settings['EditorAreaCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
} }
} }

View File

@ -23,6 +23,10 @@ Drupal.wysiwyg.editor.init.ckeditor = function(settings) {
} }
} }
} }
// Register Font styles (versions 3.2.1 and above).
if (Drupal.settings.wysiwyg.configs.ckeditor[format].stylesSet) {
CKEDITOR.stylesSet.add(format, Drupal.settings.wysiwyg.configs.ckeditor[format].stylesSet);
}
} }
}; };
@ -34,6 +38,8 @@ Drupal.wysiwyg.editor.attach.ckeditor = function(context, params, settings) {
// Apply editor instance settings. // Apply editor instance settings.
CKEDITOR.config.customConfig = ''; CKEDITOR.config.customConfig = '';
var $drupalToolbar = $('#toolbar', Drupal.overlayChild ? window.parent.document : document);
settings.on = { settings.on = {
instanceReady: function(ev) { instanceReady: function(ev) {
var editor = ev.editor; var editor = ev.editor;
@ -125,6 +131,19 @@ Drupal.wysiwyg.editor.attach.ckeditor = function(context, params, settings) {
focus: function(ev) { focus: function(ev) {
Drupal.wysiwyg.activeId = ev.editor.name; Drupal.wysiwyg.activeId = ev.editor.name;
},
afterCommandExec: function(ev) {
// Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
if (ev.data.name != 'maximize') {
return;
}
if (ev.data.command.state == CKEDITOR.TRISTATE_ON) {
$drupalToolbar.hide();
}
else {
$drupalToolbar.show();
}
} }
}; };
@ -139,16 +158,19 @@ Drupal.wysiwyg.editor.attach.ckeditor = function(context, params, settings) {
* containing all instances or the passed in params.field instance, but * containing all instances or the passed in params.field instance, but
* always return an array to simplify all detach functions. * always return an array to simplify all detach functions.
*/ */
Drupal.wysiwyg.editor.detach.ckeditor = function(context, params) { Drupal.wysiwyg.editor.detach.ckeditor = function (context, params, trigger) {
var method = (trigger == 'serialize') ? 'updateElement' : 'destroy';
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
var instance = CKEDITOR.instances[params.field]; var instance = CKEDITOR.instances[params.field];
if (instance) { if (instance) {
instance.destroy(); instance[method]();
} }
} }
else { else {
for (var instanceName in CKEDITOR.instances) { for (var instanceName in CKEDITOR.instances) {
CKEDITOR.instances[instanceName].destroy(); if (CKEDITOR.instances.hasOwnProperty(instanceName)) {
CKEDITOR.instances[instanceName][method]();
}
} }
} }
}; };
@ -208,9 +230,18 @@ Drupal.wysiwyg.editor.instance.ckeditor = {
// @todo Don't know if we need this yet. // @todo Don't know if we need this yet.
return content; return content;
}, },
insert: function(content) { insert: function(content) {
content = this.prepareContent(content); content = this.prepareContent(content);
CKEDITOR.instances[this.field].insertHtml(content); CKEDITOR.instances[this.field].insertHtml(content);
},
setContent: function (content) {
CKEDITOR.instances[this.field].setData(content);
},
getContent: function () {
return CKEDITOR.instances[this.field].getData();
} }
}; };

38
editors/js/epiceditor.js Normal file
View File

@ -0,0 +1,38 @@
(function($) {
/**
* Attach this editor to a target element.
*/
Drupal.wysiwyg.editor.attach.epiceditor = function (context, params, settings) {
var $target = $('#' + params.field);
var containerId = params.field + '-epiceditor';
var defaultContent = $target.val();
$target.hide().after('<div id="' + containerId + '" />');
settings.container = containerId;
settings.file = {
defaultContent: defaultContent
};
settings.theme = {
preview: '/themes/preview/preview-dark.css',
editor: '/themes/editor/' + settings.theme + '.css'
}
var editor = new EpicEditor(settings).load();
$target.data('epiceditor', editor);
};
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.epiceditor = function (context, params, trigger) {
var $target = $('#' + params.field);
var editor = $target.data('epiceditor');
$target.val(editor.exportFile());
editor.unload(function () {
$target.show();
});
};
})(jQuery);

View File

@ -21,7 +21,7 @@ Drupal.wysiwyg.editor.attach.fckeditor = function(context, params, settings) {
/** /**
* Detach a single or all editors. * Detach a single or all editors.
*/ */
Drupal.wysiwyg.editor.detach.fckeditor = function(context, params) { Drupal.wysiwyg.editor.detach.fckeditor = function (context, params, trigger) {
var instances = []; var instances = [];
if (typeof params != 'undefined' && typeof FCKeditorAPI != 'undefined') { if (typeof params != 'undefined' && typeof FCKeditorAPI != 'undefined') {
var instance = FCKeditorAPI.GetInstance(params.field); var instance = FCKeditorAPI.GetInstance(params.field);
@ -36,6 +36,11 @@ Drupal.wysiwyg.editor.detach.fckeditor = function(context, params) {
for (var instanceName in instances) { for (var instanceName in instances) {
var instance = instances[instanceName]; var instance = instances[instanceName];
instance.UpdateLinkedField(); instance.UpdateLinkedField();
if (trigger == 'serialize') {
// The editor is not being removed from the DOM, so updating the linked
// field is the only action necessary.
continue;
}
// Since we already detach the editor and update the textarea, the submit // Since we already detach the editor and update the textarea, the submit
// event handler needs to be removed to prevent data loss (in IE). // event handler needs to be removed to prevent data loss (in IE).
// FCKeditor uses 2 nested iFrames; instance.EditingArea.Window is the // FCKeditor uses 2 nested iFrames; instance.EditingArea.Window is the
@ -175,6 +180,16 @@ Drupal.wysiwyg.editor.instance.fckeditor = {
var instance = FCKeditorAPI.GetInstance(this.field); var instance = FCKeditorAPI.GetInstance(this.field);
// @see FCK.InsertHtml(), FCK.InsertElement() // @see FCK.InsertHtml(), FCK.InsertElement()
instance.InsertHtml(content); instance.InsertHtml(content);
},
getContent: function () {
var instance = FCKeditorAPI.GetInstance(this.field);
return instance.GetData();
},
setContent: function (content) {
var instance = FCKeditorAPI.GetInstance(this.field);
instance.SetHTML(content);
} }
}; };

View File

@ -40,6 +40,19 @@ for (var setting in wysiwygSettings) {
} }
} }
// Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
var oldFitWindowExecute = FCKFitWindow.prototype.Execute;
var $drupalToolbar = window.parent.jQuery('#toolbar', Drupal.overlayChild ? window.parent.window.parent.document : window.parent.document);
FCKFitWindow.prototype.Execute = function() {
oldFitWindowExecute.apply(this, arguments);
if (this.IsMaximized) {
$drupalToolbar.hide();
}
else {
$drupalToolbar.show();
}
}
/** /**
* Initialize this editor instance. * Initialize this editor instance.
*/ */

View File

@ -11,15 +11,33 @@ Drupal.wysiwyg.editor.attach.jwysiwyg = function(context, params, settings) {
/** /**
* Detach a single or all editors. * Detach a single or all editors.
*/ */
Drupal.wysiwyg.editor.detach.jwysiwyg = function(context, params) { Drupal.wysiwyg.editor.detach.jwysiwyg = function (context, params, trigger) {
var $field = $('#' + params.field); var $field = $('#' + params.field);
var editor = $field.data('wysiwyg'); var editor = $field.data('wysiwyg');
if (typeof editor != 'undefined') { if (typeof editor != 'undefined') {
editor.saveContent(); editor.saveContent();
editor.element.remove(); if (trigger != 'serialize') {
editor.element.remove();
}
} }
$field.removeData('wysiwyg'); $field.removeData('wysiwyg');
$field.show(); if (trigger != 'serialize') {
$field.show();
}
};
Drupal.wysiwyg.editor.instance.jwysiwyg = {
insert: function (content) {
$('#' + this.field).wysiwyg('insertHtml', content);
},
setContent: function (content) {
$('#' + this.field).wysiwyg('setContent', content);
},
getContent: function () {
return $('#' + this.field).wysiwyg('getContent');
}
}; };
})(jQuery); })(jQuery);

View File

@ -17,7 +17,10 @@ Drupal.wysiwyg.editor.attach.markitup = function(context, params, settings) {
/** /**
* Detach a single or all editors. * Detach a single or all editors.
*/ */
Drupal.wysiwyg.editor.detach.markitup = function(context, params) { Drupal.wysiwyg.editor.detach.markitup = function (context, params, trigger) {
if (trigger == 'serialize') {
return;
}
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
$('#' + params.field, context).markItUpRemove(); $('#' + params.field, context).markItUpRemove();
} }
@ -26,4 +29,18 @@ Drupal.wysiwyg.editor.detach.markitup = function(context, params) {
} }
}; };
Drupal.wysiwyg.editor.instance.markitup = {
insert: function (content) {
$.markItUp({ replaceWith: content });
},
setContent: function (content) {
$('#' + this.field).val(content);
},
getContent: function () {
return $('#' + this.field).val();
}
};
})(jQuery); })(jQuery);

View File

@ -30,12 +30,17 @@ Drupal.wysiwyg.editor.attach.nicedit = function(context, params, settings) {
* *
* See Drupal.wysiwyg.editor.detach.none() for a full description of this hook. * See Drupal.wysiwyg.editor.detach.none() for a full description of this hook.
*/ */
Drupal.wysiwyg.editor.detach.nicedit = function(context, params) { Drupal.wysiwyg.editor.detach.nicedit = function (context, params, trigger) {
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
var instance = nicEditors.findEditor(params.field); var instance = nicEditors.findEditor(params.field);
if (instance) { if (instance) {
instance.ne.removeInstance(params.field); if (trigger == 'serialize') {
instance.ne.removePanel(); instance.saveContent();
}
else {
instance.ne.removeInstance(params.field);
instance.ne.removePanel();
}
} }
} }
else { else {
@ -43,10 +48,17 @@ Drupal.wysiwyg.editor.detach.nicedit = function(context, params) {
// Save contents of all editors back into textareas. // Save contents of all editors back into textareas.
var instances = nicEditors.editors[e].nicInstances; var instances = nicEditors.editors[e].nicInstances;
for (var i = 0; i < instances.length; i++) { for (var i = 0; i < instances.length; i++) {
instances[i].remove(); if (trigger == 'serialize') {
instances[i].saveContent();
}
else {
instances[i].remove();
}
} }
// Remove all editor instances. // Remove all editor instances.
nicEditors.editors[e].nicInstances = []; if (trigger != 'serialize') {
nicEditors.editors[e].nicInstances = [];
}
} }
} }
}; };
@ -62,7 +74,7 @@ Drupal.wysiwyg.editor.instance.nicedit = {
// IE. // IE.
if (document.selection) { if (document.selection) {
editingArea.focus(); editingArea.focus();
sel.createRange().text = content; sel.createRange().pasteHTML(content);
} }
else { else {
// Convert selection to a range. // Convert selection to a range.
@ -89,6 +101,14 @@ Drupal.wysiwyg.editor.instance.nicedit = {
// Only fragment children are inserted. // Only fragment children are inserted.
range.insertNode(fragment); range.insertNode(fragment);
} }
},
setContent: function (content) {
nicEditors.findEditor(this.field).setContent(content);
},
getContent: function () {
return nicEditors.findEditor(this.field).getContent();
} }
}; };

View File

@ -17,7 +17,7 @@ Drupal.wysiwyg.editor.attach.none = function(context, params, settings) {
if (params.resizable) { if (params.resizable) {
var $wrapper = $('#' + params.field).parents('.form-textarea-wrapper:first'); var $wrapper = $('#' + params.field).parents('.form-textarea-wrapper:first');
$wrapper.addClass('resizable'); $wrapper.addClass('resizable');
if (Drupal.behaviors.textarea.attach) { if (Drupal.behaviors.textarea) {
Drupal.behaviors.textarea.attach(); Drupal.behaviors.textarea.attach();
} }
} }
@ -26,6 +26,9 @@ Drupal.wysiwyg.editor.attach.none = function(context, params, settings) {
/** /**
* Detach a single or all editors. * Detach a single or all editors.
* *
* The editor syncs its contents back to the original field before its instance
* is removed.
*
* @param context * @param context
* A DOM element, supplied by Drupal.attachBehaviors(). * A DOM element, supplied by Drupal.attachBehaviors().
* @param params * @param params
@ -33,9 +36,18 @@ Drupal.wysiwyg.editor.attach.none = function(context, params, settings) {
* only the editor instance in params.field should be detached. Otherwise, * only the editor instance in params.field should be detached. Otherwise,
* all editors should be detached and saved, so they can be submitted in * all editors should be detached and saved, so they can be submitted in
* AJAX/AHAH applications. * AJAX/AHAH applications.
* @param trigger
* A string describing why the editor is being detached.
* Possible triggers are:
* - unload: (default) Another or no editor is about to take its place.
* - move: Currently expected to produce the same result as unload.
* - serialize: The form is about to be serialized before an AJAX request or
* a normal form submission. If possible, perform a quick detach and leave
* the editor's GUI elements in place to avoid flashes or scrolling issues.
* @see Drupal.detachBehaviors
*/ */
Drupal.wysiwyg.editor.detach.none = function(context, params) { Drupal.wysiwyg.editor.detach.none = function (context, params, trigger) {
if (typeof params != 'undefined') { if (typeof params != 'undefined' && (trigger != 'serialize')) {
var $wrapper = $('#' + params.field).parents('.form-textarea-wrapper:first'); var $wrapper = $('#' + params.field).parents('.form-textarea-wrapper:first');
$wrapper.removeOnce('textarea').removeClass('.resizable-textarea') $wrapper.removeOnce('textarea').removeClass('.resizable-textarea')
.find('.grippie').remove(); .find('.grippie').remove();
@ -65,6 +77,14 @@ Drupal.wysiwyg.editor.instance.none = {
else { else {
editor.value += content; editor.value += content;
} }
},
setContent: function (content) {
$('#' + this.field).val(content);
},
getContent: function () {
return $('#' + this.field).val();
} }
}; };

View File

@ -23,6 +23,19 @@ WYSIWYG.getEditor = function (n) {
(function($) { (function($) {
// Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
var oldMaximize = WYSIWYG.maximize;
WYSIWYG.maximize = function (n) {
var $drupalToolbar = $('#toolbar', Drupal.overlayChild ? window.parent.document : document);
oldMaximize.apply(this, arguments);
if (this.maximized[n]) {
$drupalToolbar.hide();
}
else {
$drupalToolbar.show();
}
}
/** /**
* Attach this editor to a target element. * Attach this editor to a target element.
*/ */
@ -45,24 +58,84 @@ Drupal.wysiwyg.editor.attach.openwysiwyg = function(context, params, settings) {
/** /**
* Detach a single or all editors. * Detach a single or all editors.
*/ */
Drupal.wysiwyg.editor.detach.openwysiwyg = function(context, params) { Drupal.wysiwyg.editor.detach.openwysiwyg = function (context, params, trigger) {
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
var instance = WYSIWYG.config[params.field]; var instance = WYSIWYG.config[params.field];
if (typeof instance != 'undefined') { if (typeof instance != 'undefined') {
WYSIWYG.updateTextArea(params.field); WYSIWYG.updateTextArea(params.field);
jQuery('#wysiwyg_div_' + params.field).remove(); if (trigger != 'serialize') {
delete instance; jQuery('#wysiwyg_div_' + params.field).remove();
delete instance;
}
}
if (trigger != 'serialize') {
jQuery('#' + params.field).show();
} }
jQuery('#' + params.field).show();
} }
else { else {
jQuery.each(WYSIWYG.config, function(field) { jQuery.each(WYSIWYG.config, function(field) {
WYSIWYG.updateTextArea(field); WYSIWYG.updateTextArea(field);
jQuery('#wysiwyg_div_' + field).remove(); if (trigger != 'serialize') {
delete this; jQuery('#wysiwyg_div_' + field).remove();
jQuery('#' + field).show(); delete this;
jQuery('#' + field).show();
}
}); });
} }
}; };
/**
* Instance methods for openWYSIWYG.
*/
Drupal.wysiwyg.editor.instance.openwysiwyg = {
insert: function (content) {
// If IE has dropped focus content will be inserted at the top of the page.
$('#wysiwyg' + this.field).contents().find('body').focus();
WYSIWYG.insertHTML(content, this.field);
},
setContent: function (content) {
// Based on openWYSIWYG's _generate() method.
var doc = WYSIWYG.getEditorWindow(this.field).document;
if (WYSIWYG.config[this.field].ReplaceLineBreaks) {
content = content.replace(/\n\r|\n/ig, '<br />');
}
if (WYSIWYG.viewTextMode[this.field]) {
var html = document.createTextNode(content);
doc.body.innerHTML = '';
doc.body.appendChild(html);
}
else {
doc.open();
doc.write(content);
doc.close();
}
},
getContent: function () {
// Based on openWYSIWYG's updateTextarea() method.
var content = '';
var doc = WYSIWYG.getEditorWindow(this.field).document;
if (WYSIWYG.viewTextMode[this.field]) {
if (WYSIWYG_Core.isMSIE) {
content = doc.body.innerText;
}
else {
var range = doc.body.ownerDocument.createRange();
range.selectNodeContents(doc.body);
content = range.toString();
}
}
else {
content = doc.body.innerHTML;
}
content = WYSIWYG.stripURLPath(this.field, content);
content = WYSIWYG_Core.replaceRGBWithHexColor(content);
if (WYSIWYG.config[this.field].ReplaceLineBreaks) {
content = content.replace(/(\r\n)|(\n)/ig, '');
}
return content;
}
};
})(jQuery); })(jQuery);

View File

@ -10,18 +10,8 @@
* An object containing editor settings for each input format. * An object containing editor settings for each input format.
*/ */
Drupal.wysiwyg.editor.init.tinymce = function(settings) { Drupal.wysiwyg.editor.init.tinymce = function(settings) {
// If JS compression is enabled, TinyMCE is unable to autodetect its global
// settinge, hence we need to define them manually.
// @todo Move global library settings somewhere else.
tinyMCE.baseURL = settings.global.editorBasePath;
tinyMCE.srcMode = (settings.global.execMode == 'src' ? '_src' : '');
tinyMCE.gzipMode = (settings.global.execMode == 'gzip');
// Initialize editor configurations. // Initialize editor configurations.
for (var format in settings) { for (var format in settings) {
if (format == 'global') {
continue;
}
tinyMCE.init(settings[format]); tinyMCE.init(settings[format]);
if (Drupal.settings.wysiwyg.plugins[format]) { if (Drupal.settings.wysiwyg.plugins[format]) {
// Load native external plugins. // Load native external plugins.
@ -67,7 +57,7 @@ Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) {
* *
* See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook. * See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook.
*/ */
Drupal.wysiwyg.editor.detach.tinymce = function(context, params) { Drupal.wysiwyg.editor.detach.tinymce = function (context, params, trigger) {
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
tinyMCE.removeMCEControl(tinyMCE.getEditorId(params.field)); tinyMCE.removeMCEControl(tinyMCE.getEditorId(params.field));
$('#' + params.field).removeAttr('style'); $('#' + params.field).removeAttr('style');

View File

@ -11,19 +11,21 @@
* An object containing editor settings for each input format. * An object containing editor settings for each input format.
*/ */
Drupal.wysiwyg.editor.init.tinymce = function(settings) { Drupal.wysiwyg.editor.init.tinymce = function(settings) {
// If JS compression is enabled, TinyMCE is unable to autodetect its global // Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
// settinge, hence we need to define them manually. var $drupalToolbar = $('#toolbar', Drupal.overlayChild ? window.parent.document : document);
// @todo Move global library settings somewhere else. tinyMCE.onAddEditor.add(function (mgr, ed) {
tinyMCE.baseURL = settings.global.editorBasePath; if (ed.id == 'mce_fullscreen') {
tinyMCE.srcMode = (settings.global.execMode == 'src' ? '_src' : ''); $drupalToolbar.hide();
tinyMCE.gzipMode = (settings.global.execMode == 'gzip'); }
});
tinyMCE.onRemoveEditor.add(function (mgr, ed) {
if (ed.id == 'mce_fullscreen') {
$drupalToolbar.show();
}
});
// Initialize editor configurations. // Initialize editor configurations.
for (var format in settings) { for (var format in settings) {
if (format == 'global') {
continue;
};
tinyMCE.init(settings[format]);
if (Drupal.settings.wysiwyg.plugins[format]) { if (Drupal.settings.wysiwyg.plugins[format]) {
// Load native external plugins. // Load native external plugins.
// Array syntax required; 'native' is a predefined token in JavaScript. // Array syntax required; 'native' is a predefined token in JavaScript.
@ -50,6 +52,8 @@ Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) {
ed.onEvent.add(function(ed, e) { ed.onEvent.add(function(ed, e) {
Drupal.wysiwyg.activeId = ed.id; Drupal.wysiwyg.activeId = ed.id;
}); });
// Indicate that the DOM has been loaded (in case of Ajax).
tinymce.dom.Event.domLoaded = true;
// Make toolbar buttons wrappable (required for IE). // Make toolbar buttons wrappable (required for IE).
ed.onPostRender.add(function (ed) { ed.onPostRender.add(function (ed) {
var $toolbar = $('<div class="wysiwygToolbar"></div>'); var $toolbar = $('<div class="wysiwygToolbar"></div>');
@ -79,20 +83,24 @@ Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) {
* *
* See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook. * See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook.
*/ */
Drupal.wysiwyg.editor.detach.tinymce = function(context, params) { Drupal.wysiwyg.editor.detach.tinymce = function (context, params, trigger) {
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
var instance = tinyMCE.get(params.field); var instance = tinyMCE.get(params.field);
if (instance) { if (instance) {
instance.save(); instance.save();
instance.remove(); if (trigger != 'serialize') {
instance.remove();
}
} }
} }
else { else {
// Save contents of all editors back into textareas. // Save contents of all editors back into textareas.
tinyMCE.triggerSave(); tinyMCE.triggerSave();
// Remove all editor instances. if (trigger != 'serialize') {
for (var instance in tinyMCE.editors) { // Remove all editor instances.
tinyMCE.editors[instance].remove(); for (var instance in tinyMCE.editors) {
tinyMCE.editors[instance].remove();
}
} }
} }
}; };
@ -138,16 +146,18 @@ Drupal.wysiwyg.editor.instance.tinymce = {
// Attach: Replace plain text with HTML representations. // Attach: Replace plain text with HTML representations.
ed.onBeforeSetContent.add(function(ed, data) { ed.onBeforeSetContent.add(function(ed, data) {
var editorId = (ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id);
if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') { if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') {
data.content = Drupal.wysiwyg.plugins[plugin].attach(data.content, pluginSettings, ed.id); data.content = Drupal.wysiwyg.plugins[plugin].attach(data.content, pluginSettings, editorId);
data.content = Drupal.wysiwyg.editor.instance.tinymce.prepareContent(data.content); data.content = Drupal.wysiwyg.editor.instance.tinymce.prepareContent(data.content);
} }
}); });
// Detach: Replace HTML representations with plain text. // Detach: Replace HTML representations with plain text.
ed.onGetContent.add(function(ed, data) { ed.onGetContent.add(function(ed, data) {
var editorId = (ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id);
if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') { if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') {
data.content = Drupal.wysiwyg.plugins[plugin].detach(data.content, pluginSettings, ed.id); data.content = Drupal.wysiwyg.plugins[plugin].detach(data.content, pluginSettings, editorId);
} }
}); });
@ -175,7 +185,7 @@ Drupal.wysiwyg.editor.instance.tinymce = {
}, },
openDialog: function(dialog, params) { openDialog: function(dialog, params) {
var instanceId = this.isFullscreen() ? 'mce_fullscreen' : this.field; var instanceId = this.getInstanceId();
var editor = tinyMCE.get(instanceId); var editor = tinyMCE.get(instanceId);
editor.windowManager.open({ editor.windowManager.open({
file: dialog.url + '/' + instanceId, file: dialog.url + '/' + instanceId,
@ -186,8 +196,7 @@ Drupal.wysiwyg.editor.instance.tinymce = {
}, },
closeDialog: function(dialog) { closeDialog: function(dialog) {
var instanceId = this.isFullscreen() ? 'mce_fullscreen' : this.field; var editor = tinyMCE.get(this.getInstanceId());
var editor = tinyMCE.get(instanceId);
editor.windowManager.close(dialog); editor.windowManager.close(dialog);
}, },
@ -222,13 +231,25 @@ Drupal.wysiwyg.editor.instance.tinymce = {
insert: function(content) { insert: function(content) {
content = this.prepareContent(content); content = this.prepareContent(content);
var instanceId = this.isFullscreen() ? 'mce_fullscreen' : this.field; tinyMCE.execInstanceCommand(this.getInstanceId(), 'mceInsertContent', false, content);
tinyMCE.execInstanceCommand(instanceId, 'mceInsertContent', false, content); },
setContent: function (content) {
content = this.prepareContent(content);
tinyMCE.execInstanceCommand(this.getInstanceId(), 'mceSetContent', false, content);
},
getContent: function () {
return tinyMCE.get(this.getInstanceId()).getContent();
}, },
isFullscreen: function() { isFullscreen: function() {
// TinyMCE creates a completely new instance for fullscreen mode. // TinyMCE creates a completely new instance for fullscreen mode.
return tinyMCE.activeEditor.id == 'mce_fullscreen' && tinyMCE.activeEditor.getParam('fullscreen_editor_id') == this.field; return tinyMCE.activeEditor.id == 'mce_fullscreen' && tinyMCE.activeEditor.getParam('fullscreen_editor_id') == this.field;
},
getInstanceId: function () {
return this.isFullscreen() ? 'mce_fullscreen' : this.field;
} }
}; };

View File

@ -80,39 +80,28 @@ Drupal.wysiwyg.editor.attach.whizzywig = function(context, params, settings) {
// Attach editor. // Attach editor.
makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all')); makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all'));
// Whizzywig fails to detect and set initial textarea contents. // Whizzywig fails to detect and set initial textarea contents.
var instance = $('#whizzy' + params.field).get(0); $('#whizzy' + params.field).contents().find('body').html(tidyD($field.val()));
if (instance) {
instance.contentWindow.document.body.innerHTML = tidyD($field.val());
}
}; };
/** /**
* Detach a single or all editors. * Detach a single or all editors.
*/ */
Drupal.wysiwyg.editor.detach.whizzywig = function(context, params) { Drupal.wysiwyg.editor.detach.whizzywig = function (context, params, trigger) {
var detach = function (index) { var detach = function (index) {
var id = whizzies[index]; var id = whizzies[index], $field = $('#' + id), instance = Drupal.wysiwyg.instances[id];
var instance = $('#whizzy' + id).get(0);
if (!instance) {
return;
}
var editingArea = instance.contentWindow.document;
var $field = $('#' + id);
// Whizzywig shows the original textarea in source mode.
if ($field.css('display') == 'block') {
editingArea.body.innerHTML = $field.val();
}
// Save contents of editor back into textarea. // Save contents of editor back into textarea.
$field.val(tidyH(editingArea)); $field.val(instance.getContent());
// If the editor is just being serialized (not detached), our work is done.
if (trigger == 'serialize') {
return;
}
// Remove editor instance. // Remove editor instance.
$('#' + id + '-whizzywig').remove(); $('#' + id + '-whizzywig').remove();
whizzies.splice(index, 1); whizzies.splice(index, 1);
// Restore original textarea styling. // Restore original textarea styling.
var originalValues = Drupal.wysiwyg.instances[id]; $field.removeAttr('style').attr('style', instance.originalStyle);
$field.removeAttr('style');
$field.attr('style', originalValues.originalStyle);
}; };
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
@ -130,4 +119,37 @@ Drupal.wysiwyg.editor.detach.whizzywig = function(context, params) {
} }
}; };
/**
* Instance methods for Whizzywig.
*/
Drupal.wysiwyg.editor.instance.whizzywig = {
insert: function (content) {
// Whizzywig executes any string beginning with 'js:'.
insHTML(content.replace(/^js:/, 'js&colon;'));
},
setContent: function (content) {
// Whizzywig shows the original textarea in source mode.
if ($field.css('display') == 'block') {
$('#' + this.field).val(content);
}
else {
var doc = $('#whizzy' + this.field).contents()[0];
doc.open();
doc.write(content);
doc.close();
}
},
getContent: function () {
// Whizzywig's tidyH() expects a document node. Clone the editing iframe's
// document so tidyH() won't mess with it if this gets called while editing.
var clone = $($('#whizzy' + this.field).contents()[0].documentElement).clone()[0].ownerDocument;
// Whizzywig shows the original textarea in source mode so update the body.
if ($field.css('display') == 'block') {
clone.body.innerHTML = $('#' + this.field).val();
}
return tidyH(clone);
}
};
})(jQuery); })(jQuery);

View File

@ -29,42 +29,31 @@ Drupal.wysiwyg.editor.attach.whizzywig = function(context, params, settings) {
// Attach editor. // Attach editor.
makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all')); makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all'));
// Whizzywig fails to detect and set initial textarea contents. // Whizzywig fails to detect and set initial textarea contents.
var instance = $('#whizzy' + params.field).get(0); $('#whizzy' + params.field).contents().find('body').html(tidyD($field.val()));
if (instance) {
instance.contentWindow.document.body.innerHTML = tidyD($field.val());
}
}; };
/** /**
* Detach a single or all editors. * Detach a single or all editors.
*/ */
Drupal.wysiwyg.editor.detach.whizzywig = function(context, params) { Drupal.wysiwyg.editor.detach.whizzywig = function (context, params, trigger) {
var detach = function (index) { var detach = function (index) {
var id = whizzies[index]; var id = whizzies[index], $field = $('#' + id), instance = Drupal.wysiwyg.instances[id];
var instance = $('#whizzy' + id).get(0);
if (!instance) {
return;
}
var editingArea = instance.contentWindow.document;
var $field = $('#' + id);
// Whizzywig shows the original textarea in source mode.
if ($field.css('display') == 'block') {
editingArea.body.innerHTML = $field.val();
}
// Save contents of editor back into textarea. // Save contents of editor back into textarea.
$field.val(tidyH(editingArea)); $field.val(instance.getContent());
// If the editor is just being serialized (not detached), our work is done.
if (trigger == 'serialize') {
return;
}
// Move original textarea back to its previous location. // Move original textarea back to its previous location.
$container = $('#CONTAINER' + id); var $container = $('#CONTAINER' + id);
$field.insertBefore($container); $field.insertBefore($container);
// Remove editor instance. // Remove editor instance.
$container.remove(); $container.remove();
whizzies.splice(index, 1); whizzies.splice(index, 1);
// Restore original textarea styling. // Restore original textarea styling.
var originalValues = Drupal.wysiwyg.instances[id]; $field.removeAttr('style').attr('style', instance.originalStyle);
$field.removeAttr('style');
$field.attr('style', originalValues.originalStyle);
} }
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
@ -82,4 +71,37 @@ Drupal.wysiwyg.editor.detach.whizzywig = function(context, params) {
} }
}; };
/**
* Instance methods for Whizzywig.
*/
Drupal.wysiwyg.editor.instance.whizzywig = {
insert: function (content) {
// Whizzywig executes any string beginning with 'js:'.
insHTML(content.replace(/^js:/, 'js&colon;'));
},
setContent: function (content) {
// Whizzywig shows the original textarea in source mode.
if ($field.css('display') == 'block') {
$('#' + this.field).val(content);
}
else {
var doc = $('#whizzy' + this.field).contents()[0];
doc.open();
doc.write(content);
doc.close();
}
},
getContent: function () {
// Whizzywig's tidyH() expects a document node. Clone the editing iframe's
// document so tidyH() won't mess with it if this gets called while editing.
var clone = $($('#whizzy' + this.field).contents()[0].documentElement).clone()[0].ownerDocument;
// Whizzywig shows the original textarea in source mode so update the body.
if ($field.css('display') == 'block') {
clone.body.innerHTML = $('#' + this.field).val();
}
return tidyH(clone);
}
};
})(jQuery); })(jQuery);

View File

@ -71,41 +71,28 @@ Drupal.wysiwyg.editor.attach.whizzywig = function(context, params, settings) {
// Attach editor. // Attach editor.
makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all')); makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all'));
// Whizzywig fails to detect and set initial textarea contents. // Whizzywig fails to detect and set initial textarea contents.
var instance = $('#whizzy' + params.field).get(0); $('#whizzy' + params.field).contents().find('body').html(tidyD($field.val()));
if (instance) {
instance.contentWindow.document.body.innerHTML = tidyD($field.val());
}
}; };
/** /**
* Detach a single or all editors. * Detach a single or all editors.
*/ */
Drupal.wysiwyg.editor.detach.whizzywig = function(context, params) { Drupal.wysiwyg.editor.detach.whizzywig = function (context, params, trigger) {
var detach = function (index) { var detach = function (index) {
var id = whizzies[index]; var id = whizzies[index], $field = $('#' + id), instance = Drupal.wysiwyg.instances[id];
var instance = $('#whizzy' + id).get(0);
if (!instance) {
return;
}
var body = instance.contentWindow.document.body;
var $field = $('#' + id);
// Whizzywig shows the original textarea in source mode.
if ($field.css('display') == 'block') {
body.innerHTML = $field.val();
}
body.innerHTML = tidyH(body.innerHTML);
// Save contents of editor back into textarea. // Save contents of editor back into textarea.
$field.val(window.get_xhtml ? get_xhtml(body) : body.innerHTML); $field.val(instance.getContent());
$field.val($field.val().replace(location.href + '#', '#')); // If the editor is just being serialized (not detached), our work is done.
if (trigger == 'serialize') {
return;
}
// Remove editor instance. // Remove editor instance.
$('#' + id + '-whizzywig').remove(); $('#' + id + '-whizzywig').remove();
whizzies.splice(index, 1); whizzies.splice(index, 1);
// Restore original textarea styling. // Restore original textarea styling.
var originalValues = Drupal.wysiwyg.instances[id]; $field.removeAttr('style').attr('style', instance.originalStyle);
$field.removeAttr('style');
$field.attr('style', originalValues.originalStyle);
}; };
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
@ -123,4 +110,45 @@ Drupal.wysiwyg.editor.detach.whizzywig = function(context, params) {
} }
}; };
/**
* Instance methods for Whizzywig.
*/
Drupal.wysiwyg.editor.instance.whizzywig = {
insert: function (content) {
// Whizzywig executes any string beginning with 'js:'.
insHTML(content.replace(/^js:/, 'js&colon;'));
},
setContent: function (content) {
var $field = $('#' + this.field);
// Whizzywig shows the original textarea in source mode.
if ($field.css('display') == 'block') {
$field.val(content);
}
else {
var doc = $('#whizzy' + this.field).contents()[0];
doc.open();
doc.write(content);
doc.close();
}
},
getContent: function () {
var $field = $('#' + this.field),
// Whizzywig shows the original textarea in source mode.
content = ($field.css('display') == 'block' ?
$field.val() : $('#whizzy' + this.field).contents().find('body').html()
);
content = tidyH(content);
// Whizzywig's get_xhtml() addon, if defined, expects a DOM node.
if ($.isFunction(window.get_xhtml)) {
var pre = document.createElement('pre');
pre.innerHTML = content;
content = get_xhtml(pre);
}
return content.replace(location.href + '#', '#');
}
};
})(jQuery); })(jQuery);

View File

@ -19,37 +19,55 @@ Drupal.wysiwyg.editor.attach.wymeditor = function (context, params, settings) {
/** /**
* Detach a single or all editors. * Detach a single or all editors.
*/ */
Drupal.wysiwyg.editor.detach.wymeditor = function (context, params) { Drupal.wysiwyg.editor.detach.wymeditor = function (context, params, trigger) {
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
var $field = $('#' + params.field); var $field = $('#' + params.field);
var index = $field.data(WYMeditor.WYM_INDEX); var index = $field.data(WYMeditor.WYM_INDEX);
if (typeof index != 'undefined') { if (typeof index != 'undefined') {
var instance = WYMeditor.INSTANCES[index]; var instance = WYMeditor.INSTANCES[index];
instance.update(); instance.update();
$(instance._box).remove(); if (trigger != 'serialize') {
$(instance._element).show(); $(instance._box).remove();
delete instance; $(instance._element).show();
delete instance;
}
}
if (trigger != 'serialize') {
$field.show();
} }
$field.show();
} }
else { else {
jQuery.each(WYMeditor.INSTANCES, function () { jQuery.each(WYMeditor.INSTANCES, function () {
this.update(); this.update();
$(this._box).remove(); if (trigger != 'serialize') {
$(this._element).show(); $(this._box).remove();
delete this; $(this._element).show();
delete this;
}
}); });
} }
}; };
Drupal.wysiwyg.editor.instance.wymeditor = { Drupal.wysiwyg.editor.instance.wymeditor = {
insert: function (content) { insert: function (content) {
this.getInstance().insert(content);
},
setContent: function (content) {
this.getInstance().html(content);
},
getContent: function () {
return this.getInstance().xhtml();
},
getInstance: function () {
var $field = $('#' + this.field); var $field = $('#' + this.field);
var index = $field.data(WYMeditor.WYM_INDEX); var index = $field.data(WYMeditor.WYM_INDEX);
if (typeof index != 'undefined') { if (typeof index != 'undefined') {
var instance = WYMeditor.INSTANCES[index]; return WYMeditor.INSTANCES[index];
instance.insert(content);
} }
return null;
} }
}; };

118
editors/js/yui.js vendored
View File

@ -2,12 +2,70 @@
/** /**
* Attach this editor to a target element. * Attach this editor to a target element.
*
* Since buttons must be added before the editor is rendered, we add plugins
* buttons on attach event rather than in init.
*/ */
Drupal.wysiwyg.editor.attach.yui = function(context, params, settings) { Drupal.wysiwyg.editor.attach.yui = function(context, params, settings) {
// Apply theme. // Apply theme.
$('#' + params.field).parent().addClass('yui-skin-' + settings.theme); $('#' + params.field).parent().addClass('yui-skin-' + settings.theme);
// Load plugins stylesheet.
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
settings.extracss += settings.extracss+' @import "'+Drupal.settings.wysiwyg.plugins[params.format].drupal[plugin].css+'"; ';
}
// Attach editor. // Attach editor.
var editor = new YAHOO.widget.Editor(params.field, settings); var editor = new YAHOO.widget.Editor(params.field, settings);
editor.on('toolbarLoaded', function() {
// Load Drupal plugins.
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
Drupal.wysiwyg.instances[params.field].addPlugin(plugin, Drupal.settings.wysiwyg.plugins[params.format].drupal[plugin], Drupal.settings.wysiwyg.plugins.drupal[plugin]);
}
});
// Allow plugins to act on setEditorHTML.
var oldSetEditorHTML = editor.setEditorHTML;
editor.setEditorHTML = function (content) {
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
var pluginSettings = Drupal.settings.wysiwyg.plugins.drupal[plugin];
if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') {
content = Drupal.wysiwyg.plugins[plugin].attach(content, pluginSettings, params.field);
content = Drupal.wysiwyg.instances[params.field].prepareContent(content);
}
}
oldSetEditorHTML.call(this, content);
};
// Allow plugins to act on getEditorHTML.
var oldGetEditorHTML = editor.getEditorHTML;
editor.getEditorHTML = function () {
var content = oldGetEditorHTML.call(this);
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
var pluginSettings = Drupal.settings.wysiwyg.plugins.drupal[plugin];
if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') {
content = Drupal.wysiwyg.plugins[plugin].detach(content, pluginSettings, params.field);
}
}
return content;
}
// Reload the editor contents to give Drupal plugins a chance to act.
editor.on('editorContentLoaded', function (e) {
e.target.setEditorHTML(oldGetEditorHTML.call(e.target));
});
editor.on('afterNodeChange', function (e) {
for (var plugin in Drupal.settings.wysiwyg.plugins[params.format].drupal) {
if (typeof Drupal.wysiwyg.plugins[plugin].isNode == 'function') {
if (Drupal.wysiwyg.plugins[plugin].isNode(e.target._getSelectedElement())) {
this.toolbar.selectButton(plugin);
}
}
}
});
editor.render(); editor.render();
}; };
@ -16,20 +74,72 @@ Drupal.wysiwyg.editor.attach.yui = function(context, params, settings) {
* *
* See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook. * See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook.
*/ */
Drupal.wysiwyg.editor.detach.yui = function(context, params) { Drupal.wysiwyg.editor.detach.yui = function (context, params, trigger) {
var method = (trigger && trigger == 'serialize') ? 'saveHTML' : 'destroy';
if (typeof params != 'undefined') { if (typeof params != 'undefined') {
var instance = YAHOO.widget.EditorInfo.getEditorById(params.field); var instance = YAHOO.widget.EditorInfo._instances[params.field];
if (instance) { if (instance) {
instance.destroy(); instance[method]();
if (method == 'destroy') {
delete YAHOO.widget.EditorInfo._instances[params.field];
}
} }
} }
else { else {
for (var e in YAHOO.widget.EditorInfo._instances) { for (var e in YAHOO.widget.EditorInfo._instances) {
// Save contents of all editors back into textareas. // Save contents of all editors back into textareas.
var instance = YAHOO.widget.EditorInfo._instances[e]; var instance = YAHOO.widget.EditorInfo._instances[e];
instance.destroy(); instance[method]();
if (method == 'destroy') {
delete YAHOO.widget.EditorInfo._instances[e];
}
} }
} }
}; };
/**
* Instance methods for YUI Editor.
*/
Drupal.wysiwyg.editor.instance.yui = {
addPlugin: function (plugin, settings, pluginSettings) {
if (typeof Drupal.wysiwyg.plugins[plugin] != 'object') {
return;
}
var editor = YAHOO.widget.EditorInfo.getEditorById(this.field);
var button = editor.toolbar.getButtonByValue(plugin);
$(button._button).parent().css('background', 'transparent url(' + settings.icon + ') no-repeat center');
// 'this' will reference the toolbar while inside the event handler.
var instanceId = this.field;
editor.toolbar.on(plugin + 'Click', function (e) {
var selectedElement = editor._getSelectedElement();
// @todo Using .html() will cause XTHML vs HTML conflicts.
var data = {
format: 'html',
node: selectedElement,
content: $(selectedElement).html()
};
Drupal.wysiwyg.plugins[plugin].invoke(data, pluginSettings, instanceId);
});
},
prepareContent: function (content) {
var editor = YAHOO.widget.EditorInfo.getEditorById(this.field);
content = editor.cleanHTML(content);
return content;
},
insert: function (content) {
YAHOO.widget.EditorInfo.getEditorById(this.field).cmd_inserthtml(content);
},
setContent: function (content) {
YAHOO.widget.EditorInfo.getEditorById(this.field).setEditorHTML(content);
},
getContent: function () {
var instance = YAHOO.widget.EditorInfo.getEditorById(this.field);
return instance.cleanHTML(instance.getEditorHTML(content));
}
};
})(jQuery); })(jQuery);

View File

@ -77,13 +77,13 @@ function wysiwyg_nicedit_settings($editor, $config, $theme) {
// Add editor content stylesheet. // Add editor content stylesheet.
if (isset($config['css_setting'])) { if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') { if ($config['css_setting'] == 'theme') {
$css = path_to_theme() . '/style.css'; $css = drupal_get_path('theme', variable_get('theme_default', NULL)) . '/style.css';
if (file_exists($css)) { if (file_exists($css)) {
$settings['externalCSS'] = base_path() . $css; $settings['externalCSS'] = base_path() . $css;
} }
} }
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['externalCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); $settings['externalCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
} }
} }

View File

@ -102,8 +102,8 @@ function wysiwyg_openwysiwyg_settings($editor, $config, $theme) {
if ($config['css_setting'] == 'theme') { if ($config['css_setting'] == 'theme') {
$settings['CSSFile'] = reset(wysiwyg_get_css()); $settings['CSSFile'] = reset(wysiwyg_get_css());
} }
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['CSSFile'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); $settings['CSSFile'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
} }
} }

View File

@ -28,6 +28,7 @@ function wysiwyg_tinymce_editor() {
), ),
'version callback' => 'wysiwyg_tinymce_version', 'version callback' => 'wysiwyg_tinymce_version',
'themes callback' => 'wysiwyg_tinymce_themes', 'themes callback' => 'wysiwyg_tinymce_themes',
'init callback' => 'wysiwyg_tinymce_init',
'settings callback' => 'wysiwyg_tinymce_settings', 'settings callback' => 'wysiwyg_tinymce_settings',
'plugin callback' => 'wysiwyg_tinymce_plugins', 'plugin callback' => 'wysiwyg_tinymce_plugins',
'plugin settings callback' => 'wysiwyg_tinymce_plugin_settings', 'plugin settings callback' => 'wysiwyg_tinymce_plugin_settings',
@ -125,6 +126,40 @@ function wysiwyg_tinymce_themes($editor, $profile) {
return array('advanced', 'simple'); return array('advanced', 'simple');
} }
/**
* Returns an initialization JavaScript for this editor library.
*
* @param array $editor
* The editor library definition.
* @param string $library
* The library variant key from $editor['libraries'].
* @param object $profile
* The (first) wysiwyg editor profile.
*
* @return string
* A string containing inline JavaScript to execute before the editor library
* script is loaded.
*/
function wysiwyg_tinymce_init($editor, $library) {
// TinyMCE unconditionally searches for its library filename in SCRIPT tags on
// on the page upon loading the library in order to determine the base path to
// itself. When JavaScript aggregation is enabled, this search fails and all
// relative constructed paths within TinyMCE are broken. The library has a
// tinyMCE.baseURL property, but it is not publicly documented and thus not
// reliable. The official support forum suggests to solve the issue through
// the global window.tinyMCEPreInit variable also used by various serverside
// compressor scrips available from the official website.
// @see http://www.tinymce.com/forum/viewtopic.php?id=23286
$settings = drupal_json_encode(array(
'base' => base_path() . $editor['library path'],
'suffix' => (strpos($library, 'src') !== FALSE || strpos($library, 'dev') !== FALSE ? '_src' : ''),
'query' => '',
));
return <<<EOL
window.tinyMCEPreInit = $settings;
EOL;
}
/** /**
* Return runtime editor settings for a given wysiwyg profile. * Return runtime editor settings for a given wysiwyg profile.
* *
@ -181,6 +216,7 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) {
$settings['remove_linebreaks'] = $config['remove_linebreaks']; $settings['remove_linebreaks'] = $config['remove_linebreaks'];
} }
if (isset($config['verify_html'])) { if (isset($config['verify_html'])) {
// TinyMCE performs a type-agnostic comparison on this particular setting.
$settings['verify_html'] = (bool) $config['verify_html']; $settings['verify_html'] = (bool) $config['verify_html'];
} }
@ -192,8 +228,8 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) {
if ($config['css_setting'] == 'theme') { if ($config['css_setting'] == 'theme') {
$settings['content_css'] = implode(',', wysiwyg_get_css()); $settings['content_css'] = implode(',', wysiwyg_get_css());
} }
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['content_css'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); $settings['content_css'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
} }
} }
@ -232,15 +268,15 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) {
$settings['extensions'][_wysiwyg_tinymce_plugin_name('add', $button)] = 1; $settings['extensions'][_wysiwyg_tinymce_plugin_name('add', $button)] = 1;
} }
// Add external plugins to the list of extensions. // Add external plugins to the list of extensions.
else if ($type == 'buttons' && empty($plugins[$plugin]['internal'])) { elseif ($type == 'buttons' && empty($plugins[$plugin]['internal'])) {
$settings['extensions'][_wysiwyg_tinymce_plugin_name('add', $plugin)] = 1; $settings['extensions'][_wysiwyg_tinymce_plugin_name('add', $plugin)] = 1;
} }
// Add internal buttons that also need to be loaded as extension. // Add internal buttons that also need to be loaded as extension.
else if ($type == 'buttons' && !empty($plugins[$plugin]['load'])) { elseif ($type == 'buttons' && !empty($plugins[$plugin]['load'])) {
$settings['extensions'][$plugin] = 1; $settings['extensions'][$plugin] = 1;
} }
// Add plain extensions. // Add plain extensions.
else if ($type == 'extensions' && !empty($plugins[$plugin]['load'])) { elseif ($type == 'extensions' && !empty($plugins[$plugin]['load'])) {
$settings['extensions'][$plugin] = 1; $settings['extensions'][$plugin] = 1;
} }
// Allow plugins to add valid HTML elements. // Allow plugins to add valid HTML elements.
@ -268,7 +304,7 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) {
$settings += array( $settings += array(
'theme_advanced_resize_horizontal' => FALSE, 'theme_advanced_resize_horizontal' => FALSE,
'theme_advanced_resizing_use_cookie' => FALSE, 'theme_advanced_resizing_use_cookie' => FALSE,
'theme_advanced_path_location' => isset($config['path_loc']) ? $config['path_loc'] : 'bottom', 'theme_advanced_statusbar_location' => isset($config['path_loc']) ? $config['path_loc'] : 'bottom',
'theme_advanced_resizing' => isset($config['resizing']) ? $config['resizing'] : 1, 'theme_advanced_resizing' => isset($config['resizing']) ? $config['resizing'] : 1,
'theme_advanced_toolbar_location' => isset($config['toolbar_loc']) ? $config['toolbar_loc'] : 'top', 'theme_advanced_toolbar_location' => isset($config['toolbar_loc']) ? $config['toolbar_loc'] : 'top',
'theme_advanced_toolbar_align' => isset($config['toolbar_align']) ? $config['toolbar_align'] : 'left', 'theme_advanced_toolbar_align' => isset($config['toolbar_align']) ? $config['toolbar_align'] : 'left',
@ -361,7 +397,7 @@ function _wysiwyg_tinymce_plugin_name($op, $name) {
} }
return $name; return $name;
} }
else if ($op == 'remove') { elseif ($op == 'remove') {
if (strpos($name, '-') === 0) { if (strpos($name, '-') === 0) {
return substr($name, 1); return substr($name, 1);
} }
@ -386,6 +422,8 @@ function wysiwyg_tinymce_plugins($editor) {
'link' => t('Link'), 'unlink' => t('Unlink'), 'anchor' => t('Anchor'), 'link' => t('Link'), 'unlink' => t('Unlink'), 'anchor' => t('Anchor'),
'image' => t('Image'), 'image' => t('Image'),
'cleanup' => t('Clean-up'), 'cleanup' => t('Clean-up'),
'formatselect' => t('Block format'), 'styleselect' => t('Styles'),
'fontselect' => t('Font'), 'fontsizeselect' => t('Font size'),
'forecolor' => t('Forecolor'), 'backcolor' => t('Backcolor'), 'forecolor' => t('Forecolor'), 'backcolor' => t('Backcolor'),
'sup' => t('Superscript'), 'sub' => t('Subscript'), 'sup' => t('Superscript'), 'sub' => t('Subscript'),
'blockquote' => t('Blockquote'), 'code' => t('Source code'), 'blockquote' => t('Blockquote'), 'code' => t('Source code'),
@ -402,15 +440,15 @@ function wysiwyg_tinymce_plugins($editor) {
'path' => $editor['library path'] . '/plugins/advhr', 'path' => $editor['library path'] . '/plugins/advhr',
'buttons' => array('advhr' => t('Advanced horizontal rule')), 'buttons' => array('advhr' => t('Advanced horizontal rule')),
'extended_valid_elements' => array('hr[class|width|size|noshade]'), 'extended_valid_elements' => array('hr[class|width|size|noshade]'),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advhr', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:advhr',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'advimage' => array( 'advimage' => array(
'path' => $editor['library path'] . '/plugins/advimage', 'path' => $editor['library path'] . '/plugins/advimage',
'extensions' => array('advimage' => t('Advanced image')), 'extensions' => array('advimage' => t('Advanced image')),
'extended_valid_elements' => array('img[src|alt|title|align|width|height|usemap|hspace|vspace|border|style|class|onmouseover|onmouseout|id|name]'), 'extended_valid_elements' => array('img[src|alt|title|align|width|height|usemap|hspace|vspace|border|style|class|onmouseover|onmouseout|id|name|longdesc]'),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:advimage',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
@ -418,49 +456,42 @@ function wysiwyg_tinymce_plugins($editor) {
'path' => $editor['library path'] . '/plugins/advlink', 'path' => $editor['library path'] . '/plugins/advlink',
'extensions' => array('advlink' => t('Advanced link')), 'extensions' => array('advlink' => t('Advanced link')),
'extended_valid_elements' => array('a[name|href|target|title|class|onfocus|onblur|onclick|ondlbclick|onmousedown|onmouseup|onmouseover|onmouseout|onkeypress|onkeydown|onkeyup|id|style|rel]'), 'extended_valid_elements' => array('a[name|href|target|title|class|onfocus|onblur|onclick|ondlbclick|onmousedown|onmouseup|onmouseover|onmouseout|onkeypress|onkeydown|onkeyup|id|style|rel]'),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:advlink',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'autosave' => array( 'autosave' => array(
'path' => $editor['library path'] . '/plugins/autosave', 'path' => $editor['library path'] . '/plugins/autosave',
'extensions' => array('autosave' => t('Auto save')), 'extensions' => array('autosave' => t('Auto save')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:autosave',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'contextmenu' => array( 'contextmenu' => array(
'path' => $editor['library path'] . '/plugins/contextmenu', 'path' => $editor['library path'] . '/plugins/contextmenu',
'extensions' => array('contextmenu' => t('Context menu')), 'extensions' => array('contextmenu' => t('Context menu')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/contextmenu', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:contextmenu',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'directionality' => array( 'directionality' => array(
'path' => $editor['library path'] . '/plugins/directionality', 'path' => $editor['library path'] . '/plugins/directionality',
'buttons' => array('ltr' => t('Left-to-right'), 'rtl' => t('Right-to-left')), 'buttons' => array('ltr' => t('Left-to-right'), 'rtl' => t('Right-to-left')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:directionality',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'emotions' => array( 'emotions' => array(
'path' => $editor['library path'] . '/plugins/emotions', 'path' => $editor['library path'] . '/plugins/emotions',
'buttons' => array('emotions' => t('Emotions')), 'buttons' => array('emotions' => t('Emotions')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/emotions', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:emotions',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'font' => array(
'path' => $editor['library path'] . '/plugins/font',
'buttons' => array('formatselect' => t('HTML block format'), 'fontselect' => t('Font'), 'fontsizeselect' => t('Font size'), 'styleselect' => t('Font style')),
'extended_valid_elements' => array('font[face|size|color|style],span[class|align|style]'),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/font',
'internal' => TRUE,
),
'fullscreen' => array( 'fullscreen' => array(
'path' => $editor['library path'] . '/plugins/fullscreen', 'path' => $editor['library path'] . '/plugins/fullscreen',
'buttons' => array('fullscreen' => t('Fullscreen')), 'buttons' => array('fullscreen' => t('Fullscreen')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullscreen', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:fullscreen',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
@ -470,7 +501,7 @@ function wysiwyg_tinymce_plugins($editor) {
'options' => array( 'options' => array(
'dialog_type' => array('modal'), 'dialog_type' => array('modal'),
), ),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:inlinepopups',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
@ -481,56 +512,56 @@ function wysiwyg_tinymce_plugins($editor) {
'plugin_insertdate_dateFormat' => '%Y-%m-%d', 'plugin_insertdate_dateFormat' => '%Y-%m-%d',
'plugin_insertdate_timeFormat' => '%H:%M:%S', 'plugin_insertdate_timeFormat' => '%H:%M:%S',
), ),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/insertdatetime', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:insertdatetime',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'layer' => array( 'layer' => array(
'path' => $editor['library path'] . '/plugins/layer', 'path' => $editor['library path'] . '/plugins/layer',
'buttons' => array('insertlayer' => t('Insert layer'), 'moveforward' => t('Move forward'), 'movebackward' => t('Move backward'), 'absolute' => t('Absolute')), 'buttons' => array('insertlayer' => t('Insert layer'), 'moveforward' => t('Move forward'), 'movebackward' => t('Move backward'), 'absolute' => t('Absolute')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/layer', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:layer',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'paste' => array( 'paste' => array(
'path' => $editor['library path'] . '/plugins/paste', 'path' => $editor['library path'] . '/plugins/paste',
'buttons' => array('pastetext' => t('Paste text'), 'pasteword' => t('Paste from Word'), 'selectall' => t('Select all')), 'buttons' => array('pastetext' => t('Paste text'), 'pasteword' => t('Paste from Word'), 'selectall' => t('Select all')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:paste',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'preview' => array( 'preview' => array(
'path' => $editor['library path'] . '/plugins/preview', 'path' => $editor['library path'] . '/plugins/preview',
'buttons' => array('preview' => t('Preview')), 'buttons' => array('preview' => t('Preview')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/preview', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:preview',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'print' => array( 'print' => array(
'path' => $editor['library path'] . '/plugins/print', 'path' => $editor['library path'] . '/plugins/print',
'buttons' => array('print' => t('Print')), 'buttons' => array('print' => t('Print')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/print', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:print',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'searchreplace' => array( 'searchreplace' => array(
'path' => $editor['library path'] . '/plugins/searchreplace', 'path' => $editor['library path'] . '/plugins/searchreplace',
'buttons' => array('search' => t('Search'), 'replace' => t('Replace')), 'buttons' => array('search' => t('Search'), 'replace' => t('Replace')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/searchreplace', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:searchreplace',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'style' => array( 'style' => array(
'path' => $editor['library path'] . '/plugins/style', 'path' => $editor['library path'] . '/plugins/style',
'buttons' => array('styleprops' => t('Style properties')), 'buttons' => array('styleprops' => t('Advanced CSS styles')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:style',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
'table' => array( 'table' => array(
'path' => $editor['library path'] . '/plugins/table', 'path' => $editor['library path'] . '/plugins/table',
'buttons' => array('tablecontrols' => t('Table')), 'buttons' => array('tablecontrols' => t('Table')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:table',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
), ),
@ -540,7 +571,6 @@ function wysiwyg_tinymce_plugins($editor) {
'path' => $editor['library path'] . '/plugins/flash', 'path' => $editor['library path'] . '/plugins/flash',
'buttons' => array('flash' => t('Flash')), 'buttons' => array('flash' => t('Flash')),
'extended_valid_elements' => array('img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name|obj|param|embed]'), 'extended_valid_elements' => array('img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name|obj|param|embed]'),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/flash',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
); );
@ -549,14 +579,14 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['media'] = array( $plugins['media'] = array(
'path' => $editor['library path'] . '/plugins/media', 'path' => $editor['library path'] . '/plugins/media',
'buttons' => array('media' => t('Media')), 'buttons' => array('media' => t('Media')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:media',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
); );
$plugins['xhtmlxtras'] = array( $plugins['xhtmlxtras'] = array(
'path' => $editor['library path'] . '/plugins/xhtmlxtras', 'path' => $editor['library path'] . '/plugins/xhtmlxtras',
'buttons' => array('cite' => t('Citation'), 'del' => t('Deleted'), 'abbr' => t('Abbreviation'), 'acronym' => t('Acronym'), 'ins' => t('Inserted'), 'attribs' => t('HTML attributes')), 'buttons' => array('cite' => t('Citation'), 'del' => t('Deleted'), 'abbr' => t('Abbreviation'), 'acronym' => t('Acronym'), 'ins' => t('Inserted'), 'attribs' => t('HTML attributes')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:xhtmlxtras',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
); );
@ -565,7 +595,7 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['bbcode'] = array( $plugins['bbcode'] = array(
'path' => $editor['library path'] . '/plugins/bbcode', 'path' => $editor['library path'] . '/plugins/bbcode',
'extensions' => array('bbcode' => t('BBCode')), 'extensions' => array('bbcode' => t('BBCode')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/bbcode', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:bbcode',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
); );
@ -573,7 +603,6 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['safari'] = array( $plugins['safari'] = array(
'path' => $editor['library path'] . '/plugins/safari', 'path' => $editor['library path'] . '/plugins/safari',
'extensions' => array('safari' => t('Safari compatibility')), 'extensions' => array('safari' => t('Safari compatibility')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/safari',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
); );
@ -583,7 +612,7 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['autoresize'] = array( $plugins['autoresize'] = array(
'path' => $editor['library path'] . '/plugins/autoresize', 'path' => $editor['library path'] . '/plugins/autoresize',
'extensions' => array('autoresize' => t('Auto resize')), 'extensions' => array('autoresize' => t('Auto resize')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autoresize', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:autoresize',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
); );
@ -592,7 +621,7 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['advlist'] = array( $plugins['advlist'] = array(
'path' => $editor['library path'] . '/plugins/advlist', 'path' => $editor['library path'] . '/plugins/advlist',
'extensions' => array('advlist' => t('Advanced list')), 'extensions' => array('advlist' => t('Advanced list')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlist', 'url' => 'http://www.tinymce.com/wiki.php/Plugin:advlist',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
); );
@ -601,11 +630,24 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['wordcount'] = array( $plugins['wordcount'] = array(
'path' => $editor['library path'] . '/plugins/wordcount', 'path' => $editor['library path'] . '/plugins/wordcount',
'extensions' => array('wordcount' => t('Word count')), 'extensions' => array('wordcount' => t('Word count')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/wordcount',
'internal' => TRUE, 'internal' => TRUE,
'load' => TRUE, 'load' => TRUE,
); );
} }
if (version_compare($editor['installed version'], '3.4.1', '>=')) {
$plugins['lists'] = array(
'path' => $editor['library path'] . 'plugins/lists',
'extensions' => array('lists' => t('List normalizer')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:lists',
'internal' => TRUE,
'load' => TRUE,
'extended_valid_elements' => array(
'li[class|dir|id|lang|onclick|ondblclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|style|title|type|value]',
'ol[class|compact|dir|id|lang|onclick|ondblclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|start|style|title|type]',
'ul[class|compact|dir|id|lang|onclick|ondblclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|style|title|type]',
),
);
}
return $plugins; return $plugins;
} }

View File

@ -104,13 +104,13 @@ function wysiwyg_whizzywig_settings($editor, $config, $theme) {
// Add editor content stylesheet. // Add editor content stylesheet.
if (isset($config['css_setting'])) { if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') { if ($config['css_setting'] == 'theme') {
$css = path_to_theme() . '/style.css'; $css = drupal_get_path('theme', variable_get('theme_default', NULL)) . '/style.css';
if (file_exists($css)) { if (file_exists($css)) {
$settings['externalCSS'] = base_path() . $css; $settings['externalCSS'] = base_path() . $css;
} }
} }
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['externalCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); $settings['externalCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
} }
} }

View File

@ -172,10 +172,11 @@ function wysiwyg_wymeditor_settings($editor, $config, $theme) {
if (isset($config['css_setting'])) { if (isset($config['css_setting'])) {
if ($config['css_setting'] == 'theme') { if ($config['css_setting'] == 'theme') {
// WYMeditor only supports one CSS file currently. // WYMeditor only supports one CSS file currently.
$settings['stylesheet'] = reset(wysiwyg_get_css()); $css = wysiwyg_get_css();
$settings['stylesheet'] = reset($css);
} }
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['stylesheet'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); $settings['stylesheet'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
} }
} }
@ -190,7 +191,7 @@ function wysiwyg_wymeditor_plugins($editor) {
'default' => array( 'default' => array(
'buttons' => array( 'buttons' => array(
'Bold' => t('Bold'), 'Italic' => t('Italic'), 'Bold' => t('Bold'), 'Italic' => t('Italic'),
'InsertOrderedList' => t('Bullet list'), 'InsertUnorderedList' => t('Numbered list'), 'InsertOrderedList' => t('Numbered list'), 'InsertUnorderedList' => t('Bullet list'),
'Outdent' => t('Outdent'), 'Indent' => t('Indent'), 'Outdent' => t('Outdent'), 'Indent' => t('Indent'),
'Undo' => t('Undo'), 'Redo' => t('Redo'), 'Undo' => t('Undo'), 'Redo' => t('Redo'),
'CreateLink' => t('Link'), 'Unlink' => t('Unlink'), 'CreateLink' => t('Link'), 'Unlink' => t('Unlink'),
@ -212,22 +213,22 @@ function wysiwyg_wymeditor_plugins($editor) {
*/ */
function _wysiwyg_wymeditor_button_info() { function _wysiwyg_wymeditor_button_info() {
return array( return array(
'Bold' => array('title'=> 'Strong', 'css'=> 'wym_tools_strong'), 'Bold' => array('title' => 'Strong', 'css' => 'wym_tools_strong'),
'Italic' => array('title'=> 'Emphasis', 'css'=> 'wym_tools_emphasis'), 'Italic' => array('title' => 'Emphasis', 'css' => 'wym_tools_emphasis'),
'Superscript' => array('title'=> 'Superscript', 'css'=> 'wym_tools_superscript'), 'Superscript' => array('title' => 'Superscript', 'css' => 'wym_tools_superscript'),
'Subscript' => array('title'=> 'Subscript', 'css'=> 'wym_tools_subscript'), 'Subscript' => array('title' => 'Subscript', 'css' => 'wym_tools_subscript'),
'InsertOrderedList' => array('title'=> 'Ordered_List', 'css'=> 'wym_tools_ordered_list'), 'InsertOrderedList' => array('title' => 'Ordered_List', 'css' => 'wym_tools_ordered_list'),
'InsertUnorderedList' => array('title'=> 'Unordered_List', 'css'=> 'wym_tools_unordered_list'), 'InsertUnorderedList' => array('title' => 'Unordered_List', 'css' => 'wym_tools_unordered_list'),
'Indent' => array('title'=> 'Indent', 'css'=> 'wym_tools_indent'), 'Indent' => array('title' => 'Indent', 'css' => 'wym_tools_indent'),
'Outdent' => array('title'=> 'Outdent', 'css'=> 'wym_tools_outdent'), 'Outdent' => array('title' => 'Outdent', 'css' => 'wym_tools_outdent'),
'Undo' => array('title'=> 'Undo', 'css'=> 'wym_tools_undo'), 'Undo' => array('title' => 'Undo', 'css' => 'wym_tools_undo'),
'Redo' => array('title'=> 'Redo', 'css'=> 'wym_tools_redo'), 'Redo' => array('title' => 'Redo', 'css' => 'wym_tools_redo'),
'CreateLink' => array('title'=> 'Link', 'css'=> 'wym_tools_link'), 'CreateLink' => array('title' => 'Link', 'css' => 'wym_tools_link'),
'Unlink' => array('title'=> 'Unlink', 'css'=> 'wym_tools_unlink'), 'Unlink' => array('title' => 'Unlink', 'css' => 'wym_tools_unlink'),
'InsertImage' => array('title'=> 'Image', 'css'=> 'wym_tools_image'), 'InsertImage' => array('title' => 'Image', 'css' => 'wym_tools_image'),
'InsertTable' => array('title'=> 'Table', 'css'=> 'wym_tools_table'), 'InsertTable' => array('title' => 'Table', 'css' => 'wym_tools_table'),
'Paste' => array('title'=> 'Paste_From_Word', 'css'=> 'wym_tools_paste'), 'Paste' => array('title' => 'Paste_From_Word', 'css' => 'wym_tools_paste'),
'ToggleHtml' => array('title'=> 'HTML', 'css'=> 'wym_tools_html'), 'ToggleHtml' => array('title' => 'HTML', 'css' => 'wym_tools_html'),
'Preview' => array('title'=> 'Preview', 'css'=> 'wym_tools_preview'), 'Preview' => array('title' => 'Preview', 'css' => 'wym_tools_preview'),
); );
} }

View File

@ -45,6 +45,14 @@ function wysiwyg_yui_editor() {
'load callback' => 'wysiwyg_yui_load', 'load callback' => 'wysiwyg_yui_load',
'settings callback' => 'wysiwyg_yui_settings', 'settings callback' => 'wysiwyg_yui_settings',
'plugin callback' => 'wysiwyg_yui_plugins', 'plugin callback' => 'wysiwyg_yui_plugins',
'plugin settings callback' => 'wysiwyg_yui_plugin_settings',
'proxy plugin' => array(
'drupal' => array(
'load' => TRUE,
'proxy' => TRUE,
),
),
'proxy plugin settings callback' => 'wysiwyg_yui_proxy_plugin_settings',
'versions' => array( 'versions' => array(
'2.7.0' => array( '2.7.0' => array(
'js files' => array('yui.js'), 'js files' => array('yui.js'),
@ -177,7 +185,7 @@ function wysiwyg_yui_settings($editor, $config, $theme) {
} }
} }
} }
else if ($button == 'fontname') { elseif ($button == 'fontname') {
$extra = array('menu' => array( $extra = array('menu' => array(
array('text' => 'Arial', 'checked' => TRUE), array('text' => 'Arial', 'checked' => TRUE),
array('text' => 'Arial Black'), array('text' => 'Arial Black'),
@ -202,8 +210,8 @@ function wysiwyg_yui_settings($editor, $config, $theme) {
if ($config['css_setting'] == 'theme') { if ($config['css_setting'] == 'theme') {
$settings['extracss'] = wysiwyg_get_css(); $settings['extracss'] = wysiwyg_get_css();
} }
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['extracss'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); $settings['extracss'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => drupal_get_path('theme', variable_get('theme_default', NULL))));
$settings['extracss'] = explode(',', $settings['extracss']); $settings['extracss'] = explode(',', $settings['extracss']);
} }
// YUI only supports inline CSS, so we need to use @import directives. // YUI only supports inline CSS, so we need to use @import directives.
@ -233,8 +241,7 @@ function wysiwyg_yui_button_setting($editor, $plugin, $button, $extra = array())
static $plugins; static $plugins;
if (!isset($plugins)) { if (!isset($plugins)) {
// @todo Invoke all enabled plugins, not just internals. $plugins = wysiwyg_get_plugins($editor['name']);
$plugins = wysiwyg_yui_plugins($editor);
} }
// Return a simple separator. // Return a simple separator.
@ -269,6 +276,41 @@ function wysiwyg_yui_button_setting($editor, $plugin, $button, $extra = array())
return $button; return $button;
} }
/**
* Build a JS settings array of native external plugins that need to be loaded separately.
*/
function wysiwyg_yui_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
if (!empty($plugin['load'])) {
// Add path for native external plugins; internal ones are loaded
// automatically.
if (empty($plugin['internal']) && isset($plugin['path'])) {
$settings[$name] = base_path() . $plugin['path'];
}
}
}
return $settings;
}
/**
* Build a JS settings array for Drupal plugins loaded via the proxy plugin.
*/
function wysiwyg_yui_proxy_plugin_settings($editor, $profile, $plugins) {
$settings = array();
foreach ($plugins as $name => $plugin) {
// Populate required plugin settings.
$settings[$name] = $plugin['dialog settings'] + array(
'title' => $plugin['title'],
'icon' => base_path() . $plugin['icon path'] . '/' . $plugin['icon file'],
'iconTitle' => $plugin['icon title'],
// @todo These should only be set if the plugin defined them.
'css' => base_path() . $plugin['css path'] . '/' . $plugin['css file'],
);
}
return $settings;
}
/** /**
* Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin(). * Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin().
*/ */

View File

@ -6,9 +6,9 @@ hidden = TRUE
dependencies[] = wysiwyg dependencies[] = wysiwyg
files[] = wysiwyg_test.module files[] = wysiwyg_test.module
; Information added by drupal.org packaging script on 2011-06-19 ; Information added by drupal.org packaging script on 2012-10-02
version = "7.x-2.1" version = "7.x-2.2"
core = "7.x" core = "7.x"
project = "wysiwyg" project = "wysiwyg"
datestamp = "1308450722" datestamp = "1349213776"

View File

@ -5,3 +5,46 @@
* Testing functionality for Wysiwyg module. * Testing functionality for Wysiwyg module.
*/ */
/**
* Implements hook_menu().
*/
function wysiwyg_test_menu() {
$items['wysiwyg-test/ajax'] = array(
'title' => 'Ajaxified form',
'page callback' => 'drupal_get_form',
'page arguments' => array('wysiwyg_test_ajax_form'),
'access callback' => TRUE,
);
return $items;
}
/**
* Form constructor for an ajaxified form lazy-loading a textarea.
*/
function wysiwyg_test_ajax_form($form, &$form_state) {
$form['enable'] = array(
'#type' => 'checkbox',
'#title' => 'Load textarea',
'#ajax' => array(
'callback' => 'wysiwyg_test_ajax_form_callback',
'wrapper' => 'ajax-wrapper',
),
);
$form['wrapper'] = array(
'#type' => 'container',
'#id' => 'ajax-wrapper',
);
return $form;
}
/**
* #ajax callback for wysiwyg_test_ajax_form().
*/
function wysiwyg_test_ajax_form_callback($form, &$form_state) {
$form['body'] = array(
'#type' => 'text_format',
'#default_value' => '',
);
form_builder($form['form_id']['#value'], $form, $form_state);
return $form['body'];
}

View File

@ -2,83 +2,27 @@
/** /**
* @file * @file
* Theme template to display a single Wysiwyg (plugin) dialog page. * Theme implementation to display a single Wysiwyg (plugin) dialog page.
*
* Available variables:
*
* General utility variables:
* - $base_path: The base URL path of the Drupal installation. At the very
* least, this will always default to /.
* - $css: An array of CSS files for the current page.
* - $directory: The directory the theme is located in, e.g. themes/garland or
* themes/garland/minelli.
* - $logged_in: TRUE if the user is registered and signed in.
* - $is_admin: TRUE if the user has permission to access administration pages.
*
* Page metadata:
* - $language: (object) The language the site is being displayed in.
* $language->language contains its textual representation.
* $language->dir contains the language direction. It will either be 'ltr' or 'rtl'.
* - $head_title: A modified version of the page title, for use in the TITLE tag.
* - $head: Markup for the HEAD section (including meta tags, keyword tags, and
* so on).
* - $styles: Style tags necessary to import all CSS files for the page.
* - $scripts: Script tags necessary to load the JavaScript files and settings
* for the page.
*
* Site identity:
* - $site_name: The name of the site, empty when display has been disabled
* in theme settings.
*
* Page content (in order of occurrance in the default page.tpl.php):
* - $breadcrumb: The breadcrumb trail for the current page.
* - $title: The page title, for use in the actual HTML content.
* - $help: Dynamic help text, mostly for admin pages.
* - $messages: HTML for status and error messages. Should be displayed prominently.
* - $tabs: Tabs linking to any sub-pages beneath the current page (e.g., the view
* and edit tabs when displaying a node).
*
* - $content: The main content of the current Drupal page.
*
* Footer/closing data:
* - $footer : The footer region.
* - $closure: Final closing markup from any modules that have altered the page.
* This variable should always be output last, after all other dynamic content.
*
* @see template_preprocess()
* @see template_preprocess_wysiwyg_dialog_page()
*/ */
?> ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language ?>" lang="<?php print $language->language ?>" dir="<?php print $language->dir ?>">
<head>
<title><?php print $head_title; ?></title>
<?php print $head; ?>
<?php print $styles; ?>
<?php print $scripts; ?>
<script type="text/javascript"><?php /* Needed to avoid Flash of Unstyled Content in IE */ ?> </script>
</head>
<body>
<div id="page"> <div id="page">
<div id="container" class="clear-block">
<div id="main" class="column">
<?php if (!empty($breadcrumb)): ?><div id="breadcrumb"><?php print $breadcrumb; ?></div><?php endif; ?>
<div id="content"> <?php print $messages; ?>
<?php if (!empty($title)): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?>
<?php if (!empty($tabs)): ?><div class="tabs"><?php print $tabs; ?></div><?php endif; ?>
<?php if (!empty($messages)): print $messages; endif; ?>
<?php if (!empty($help)): print $help; endif; ?>
<div id="content-content" class="clear-block">
<?php print $content; ?>
</div>
</div>
</div> <div id="main-wrapper"><div id="main" class="clearfix">
</div>
</div> <div id="content" class="column"><div class="section">
<?php print $closure; ?> <a id="main-content"></a>
</body> <?php print render($title_prefix); ?>
</html> <?php if ($title): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?>
<?php print render($title_suffix); ?>
<?php if ($tabs): ?><div class="tabs"><?php print render($tabs); ?></div><?php endif; ?>
<?php print render($page['help']); ?>
<?php if ($action_links): ?><ul class="action-links"><?php print render($action_links); ?></ul><?php endif; ?>
<?php print render($page['content']); ?>
</div></div> <!-- /.section, /#content -->
</div></div> <!-- /#main, /#main-wrapper -->
</div> <!-- /#page -->

View File

@ -135,21 +135,22 @@ function wysiwyg_profile_form($form, &$form_state, $profile) {
} }
$icon = file_exists($img_src) ? '<img src="' . base_path() . $img_src . '" title="' . $button . '" style="border: 1px solid grey; vertical-align: middle;" />' : ''; $icon = file_exists($img_src) ? '<img src="' . base_path() . $img_src . '" title="' . $button . '" style="border: 1px solid grey; vertical-align: middle;" />' : '';
} }
$title = (isset($meta['url']) ? l($title, $meta['url'], array('target' => '_blank')) : $title); $title = (!empty($icon) ? $icon . ' ' . check_plain($title) : check_plain($title));
$title = (!empty($icon) ? $icon . ' ' . $title : $title);
$form['buttons'][$name][$button] = array( $form['buttons'][$name][$button] = array(
'#type' => 'checkbox', '#type' => 'checkbox',
'#title' => $title, '#title' => $title,
'#default_value' => !empty($profile->settings['buttons'][$name][$button]) ? $profile->settings['buttons'][$name][$button] : FALSE, '#default_value' => !empty($profile->settings['buttons'][$name][$button]) ? $profile->settings['buttons'][$name][$button] : FALSE,
'#description' => isset($meta['url']) ? l($meta['url'], $meta['url']) : NULL,
); );
} }
} }
else if (isset($meta['extensions']) && is_array($meta['extensions'])) { elseif (isset($meta['extensions']) && is_array($meta['extensions'])) {
foreach ($meta['extensions'] as $extension => $title) { foreach ($meta['extensions'] as $extension => $title) {
$form['buttons'][$name][$extension] = array( $form['buttons'][$name][$extension] = array(
'#type' => 'checkbox', '#type' => 'checkbox',
'#title' => isset($meta['url']) ? l($title, $meta['url'], array('target' => '_blank')) : $title, '#title' => check_plain($title),
'#default_value' => !empty($profile->settings['buttons'][$name][$extension]) ? $profile->settings['buttons'][$name][$extension] : FALSE, '#default_value' => !empty($profile->settings['buttons'][$name][$extension]) ? $profile->settings['buttons'][$name][$extension] : FALSE,
'#description' => isset($meta['url']) ? l($meta['url'], $meta['url']) : NULL,
); );
} }
} }
@ -299,6 +300,19 @@ function wysiwyg_profile_form($form, &$form_state, $profile) {
'#weight' => 110, '#weight' => 110,
); );
// Supply contextual information for other callbacks and handlers.
// @todo Modernize this form for D7+ and declare these earlier.
// $profile is the primary object of this form, and as an entity, usually
// expected to live in $form_state[$entity_type].
$form_state['wysiwyg_profile'] = $profile;
$form_state['wysiwyg']['editor'] = $editor;
$form_state['wysiwyg']['plugins'] = $plugins;
// Allow editor library specific changes to be made to the form.
if (isset($editor['settings form callback'])) {
$editor['settings form callback']($form, $form_state);
}
return $form; return $form;
} }
@ -363,14 +377,11 @@ function theme_wysiwyg_admin_button_table($variables) {
// Split checkboxes into rows with 3 columns. // Split checkboxes into rows with 3 columns.
$total = count($buttons); $total = count($buttons);
$rows = array(); $rows = array();
for ($i = 0; $i < $total; $i++) { for ($i = 0; $i < $total; $i += 3) {
$row = array(); $row = array();
$row[] = array('data' => $buttons[$i]); $row_buttons = array_slice($buttons, $i, 3) + array_fill(0, 3, array());
if (isset($buttons[++$i])) { foreach ($row_buttons as $row_button) {
$row[] = array('data' => $buttons[$i]); $row[] = array('data' => $row_button);
}
if (isset($buttons[++$i])) {
$row[] = array('data' => $buttons[$i]);
} }
$rows[] = $row; $rows[] = $row;
} }
@ -416,6 +427,11 @@ function wysiwyg_profile_overview($form, &$form_state) {
$instructions = '<p>' . t('Extract the archive and copy its contents into a new folder in the following location:<br /><code>@editor-path</code>', $targs) . '</p>'; $instructions = '<p>' . t('Extract the archive and copy its contents into a new folder in the following location:<br /><code>@editor-path</code>', $targs) . '</p>';
$instructions .= '<p>' . t('So the actual library can be found at:<br /><code>@library-filepath</code>', $targs) . '</p>'; $instructions .= '<p>' . t('So the actual library can be found at:<br /><code>@library-filepath</code>', $targs) . '</p>';
// Add any install notes.
if (!empty($editor['install note callback']) && function_exists($editor['install note callback'])) {
$instructions .= '<div class="editor-install-note">' . $editor['install note callback']() . '</div>';
}
$status[$name]['description'] .= $instructions; $status[$name]['description'] .= $instructions;
$count--; $count--;
} }
@ -457,9 +473,20 @@ function wysiwyg_profile_overview($form, &$form_state) {
// Only display editor selection for associated input formats to avoid // Only display editor selection for associated input formats to avoid
// confusion about disabled selection. // confusion about disabled selection.
if (isset($profiles[$id]) && !empty($profiles[$id]->editor)) { if (isset($profiles[$id]) && !empty($profiles[$id]->editor)) {
$editor_name = $profiles[$id]->editor;
$installed = !empty($editors[$editor_name]['installed']);
$form['formats'][$id]['editor'] = array( $form['formats'][$id]['editor'] = array(
'#markup' => $options[$profiles[$id]->editor], '#wysiwyg-editor-name' => $editor_name,
); );
if ($installed) {
$form['formats'][$id]['editor']['#markup'] = $options[$editor_name];
}
else {
drupal_set_message(t('Missing %editor library for %format format. Re-install the %editor library or delete the editor profile.', array(
'%editor' => $editors[$editor_name]['title'],
'%format' => $format->name,
)), 'warning');
}
} }
else { else {
$form['formats'][$id]['editor'] = array( $form['formats'][$id]['editor'] = array(
@ -494,17 +521,28 @@ function theme_wysiwyg_profile_overview($variables) {
if (!isset($form['formats'])) { if (!isset($form['formats'])) {
return; return;
} }
$editors = wysiwyg_get_all_editors();
$output = ''; $output = '';
$header = array(t('Input format'), t('Editor'), array('data' => t('Operations'), 'colspan' => 2)); $header = array(t('Text format'), t('Editor'), array('data' => t('Operations'), 'colspan' => 2));
$rows = array(); $rows = array();
foreach (element_children($form['formats']) as $item) { foreach (element_children($form['formats']) as $item) {
$format = &$form['formats'][$item]; $format = &$form['formats'][$item];
$rows[] = array( $row = array(
drupal_render($format['name']), 'data' => array(
drupal_render($format['editor']), drupal_render($format['name']),
isset($format['edit']) ? drupal_render($format['edit']) : '', drupal_render($format['editor']),
isset($format['delete']) ? drupal_render($format['delete']) : '', isset($format['edit']) ? drupal_render($format['edit']) : '',
isset($format['delete']) ? drupal_render($format['delete']) : '',
),
); );
if (empty($row['data'][1])) {
$row['data'][1] = array(
'data' => t('Missing library: @library', array('@library' => $editors[$format['editor']['#wysiwyg-editor-name']]['title'])),
'class' => 'error',
);
$row['class'] = array('error');
}
$rows[] = $row;
} }
$form['formats']['table']['#markup'] = theme('table', array('header' => $header, 'rows' => $rows)); $form['formats']['table']['#markup'] = theme('table', array('header' => $header, 'rows' => $rows));
$output .= drupal_render_children($form); $output .= drupal_render_children($form);
@ -554,4 +592,3 @@ function wysiwyg_profile_delete_confirm_submit($form, &$form_state) {
drupal_set_message(t('Wysiwyg profile for %name has been deleted.', array('%name' => $format->name))); drupal_set_message(t('Wysiwyg profile for %name has been deleted.', array('%name' => $format->name)));
$form_state['redirect'] = 'admin/config/content/wysiwyg'; $form_state['redirect'] = 'admin/config/content/wysiwyg';
} }

View File

@ -172,6 +172,83 @@ function hook_INCLUDE_plugin() {
return $plugins; return $plugins;
} }
/**
* Define a Wysiwyg editor library.
*
* @todo Complete this documentation.
*/
function hook_INCLUDE_editor() {
$editor['ckeditor'] = array(
// The official, human-readable label of the editor library.
'title' => 'CKEditor',
// The URL to the library's homepage.
'vendor url' => 'http://ckeditor.com',
// The URL to the library's download page.
'download url' => 'http://ckeditor.com/download',
// A definition of available variants for the editor library.
// The first defined is used by default.
'libraries' => array(
'' => array(
'title' => 'Default',
'files' => array(
'ckeditor.js' => array('preprocess' => FALSE),
),
),
'src' => array(
'title' => 'Source',
'files' => array(
'ckeditor_source.js' => array('preprocess' => FALSE),
),
),
),
// (optional) A callback to invoke to return additional notes for installing
// the editor library in the administrative list/overview.
'install note callback' => 'wysiwyg_ckeditor_install_note',
// A callback to determine the library's version.
'version callback' => 'wysiwyg_ckeditor_version',
// A callback to return available themes/skins for the editor library.
'themes callback' => 'wysiwyg_ckeditor_themes',
// (optional) A callback to perform editor-specific adjustments or
// enhancements for the administrative editor profile settings form.
'settings form callback' => 'wysiwyg_ckeditor_settings_form',
// (optional) A callback to return an initialization JavaScript snippet for
// this editor library, loaded before the actual library files. The returned
// JavaScript is executed as inline script in a primitive environment,
// before the DOM is loaded; typically used to prime a base path and other
// global window variables for the editor library before it is loaded.
// All implementations should verbosely document what they are doing and
// why that is required.
'init callback' => 'wysiwyg_ckeditor_init',
// A callback to convert administrative profile/editor settings into
// JavaScript settings.
'settings callback' => 'wysiwyg_ckeditor_settings',
// A callback to supply definitions of available editor plugins.
'plugin callback' => 'wysiwyg_ckeditor_plugins',
// A callback to convert administrative plugin settings for a editor profile
// into JavaScript settings.
'plugin settings callback' => 'wysiwyg_ckeditor_plugin_settings',
// (optional) Defines the proxy plugin that handles plugins provided by
// Drupal modules, which work in all editors that support proxy plugins.
'proxy plugin' => array(
'drupal' => array(
'load' => TRUE,
'proxy' => TRUE,
),
),
// (optional) A callback to convert proxy plugin settings into JavaScript
// settings.
'proxy plugin settings callback' => 'wysiwyg_ckeditor_proxy_plugin_settings',
// Defines the list of supported (minimum) versions of the editor library,
// and the respective Drupal integration files to load.
'versions' => array(
'3.0.0.3665' => array(
'js files' => array('ckeditor-3.0.js'),
),
),
);
return $editor;
}
/** /**
* Act on editor profile settings. * Act on editor profile settings.
* *

View File

@ -6,7 +6,68 @@
*/ */
/** /**
* Menu callback; Output a wysiwyg plugin dialog page. * Page callback; Outputs a dialog page for a wysiwyg plugin.
*
* A Wysiwyg dialog is a bare minimum, simple HTML page; presented in a
* modal/popup window, triggered via JavaScript.
*
* However, Drupal core does not support such a concept, at all.
* Insanity happens on two separate layers:
* - All HTML pages go through the default delivery callback of
* drupal_deliver_html_page(), which calls into drupal_render_page(), which
* in turn *unconditionally* invokes hook_page_build() implementations. Thus,
* block_page_build() and similar implementations add the entirety of their
* page regions and blocks to our simple dialog page.
* Obviously, we don't want that.
* - There is a nice default 'page' theme template implementation, which
* performs all the heavy-lifting that is required for outputting a sane HTML
* page through preprocess and process functions. The theme system does not
* support to "inherit" preprocess and process hooks to alternative
* implementations. Even a very basic HTML page requires almost all of that.
* However, the default page template (normally overridden by a theme)
* contains too many regions and usually also huge a header and footer.
* Obviously, we don't want that.
*
* The poor workaround would be to follow the Overlay module's implementation in
* core: override the theme, build everything, and after doing all of that,
* strip away what isn't needed. Obviously, we don't want that.
*
* Instead, we bend Drupal to sane rules:
* - This page callback returns the actual main content.
* - wysiwyg_menu() defines a custom delivery callback that replaces
* drupal_deliver_html_page(), just because we need to replace
* drupal_render_page().
* - Our replacement for drupal_render_page() builds a $page that does not use
* #type 'page' but #type 'wysiwyg_dialog_page' instead.
* - #type 'wysiwyg_dialog_page' is defined like #type 'page' in
* system_element_info(), but is required, because there's no way to inherit
* a theme definition but override the page template file to be used.
* - As a consequence, #type 'wysiwyg_dialog_page' uses
* #theme 'wysiwyg_dialog_page', for which we have to implement stub
* preprocess and process callbacks in order to call into the ones for
* #theme 'page'.
*
* As a result we get:
* - A HTML response.
* - A HTML page wrapped into html.tpl.php.
* - A page title, title prefix/suffix, messages, help, etc.pp.
* - A simple page without regions and blocks (neither built nor rendered).
*
* @see wysiwyg_menu()
* @see wysiwyg_deliver_dialog_page
* @see wysiwyg_render_dialog_page()
* @see wysiwyg_element_info()
* @see wysiwyg_theme()
* @see template_preprocess_wysiwyg_dialog_page()
* @see template_process_wysiwyg_dialog_page()
*
* @see drupal_deliver_page()
* @see drupal_deliver_html_page()
* @see drupal_render_page()
* @see system_element_info()
* @see drupal_common_theme()
* @see template_preprocess_page()
* @see template_process_page()
*/ */
function wysiwyg_dialog($plugin, $instance) { function wysiwyg_dialog($plugin, $instance) {
$plugins = wysiwyg_get_all_plugins(); $plugins = wysiwyg_get_all_plugins();
@ -27,7 +88,74 @@ function wysiwyg_dialog($plugin, $instance) {
); );
drupal_add_js(array('wysiwyg' => $settings), 'setting'); drupal_add_js(array('wysiwyg' => $settings), 'setting');
echo theme('wysiwyg_dialog_page', $callback($instance)); $build = $callback($instance);
if (!is_array($build)) {
$build = array('#markup' => $build);
}
$build += array(
'#instance' => $instance,
'#plugin' => $plugin,
);
return $build;
}
/**
* @see drupal_deliver_html_page()
*/
function wysiwyg_deliver_dialog_page($page_callback_result) {
// Menu status constants are integers; page content is a string or array.
if (is_int($page_callback_result)) {
return drupal_deliver_html_page($page_callback_result);
}
// Emit the correct charset HTTP header, but not if the page callback
// result is NULL, since that likely indicates that it printed something
// in which case, no further headers may be sent, and not if code running
// for this page request has already set the content type header.
if (isset($page_callback_result) && is_null(drupal_get_http_header('Content-Type'))) {
drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
}
// Send appropriate HTTP-Header for browsers and search engines.
global $language;
drupal_add_http_header('Content-Language', $language->language);
if (isset($page_callback_result)) {
// Print anything besides a menu constant, assuming it's not NULL or
// undefined.
print wysiwyg_render_dialog_page($page_callback_result);
}
// Perform end-of-request tasks.
drupal_page_footer();
}
/**
* @see drupal_render_page()
*/
function wysiwyg_render_dialog_page($page) {
$main_content_display = &drupal_static('system_main_content_added', FALSE);
// Allow menu callbacks to return strings or arbitrary arrays to render.
// If the array returned is not of #type page directly, we need to fill
// in the page with defaults.
if (is_string($page) || (is_array($page) && (!isset($page['#type']) || ($page['#type'] != 'page')))) {
drupal_set_page_content($page);
$page = element_info('wysiwyg_dialog_page');
}
// Modules alter the $page as needed. Blocks are populated into regions like
// 'sidebar_first', 'footer', etc.
drupal_alter(array('wysiwyg_dialog_page', 'page'), $page);
// If no module has taken care of the main content, add it to the page now.
// This allows the site to still be usable even if no modules that
// control page regions (for example, the Block module) are enabled.
if (!$main_content_display) {
$page['content']['system_main'] = drupal_set_page_content();
}
return drupal_render($page);
} }
/** /**
@ -35,29 +163,21 @@ function wysiwyg_dialog($plugin, $instance) {
* *
* @see wysiwyg_dialog() * @see wysiwyg_dialog()
* @see wysiwyg-dialog-page.tpl.php * @see wysiwyg-dialog-page.tpl.php
* @see template_preprocess() * @see template_preprocess_page()
*/ */
function template_preprocess_wysiwyg_dialog_page(&$variables) { function template_preprocess_wysiwyg_dialog_page(&$variables) {
// Construct page title template_preprocess_page($variables);
$head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal')); }
$variables['head_title'] = implode(' | ', $head_title);
$variables['base_path'] = base_path(); /**
$variables['front_page'] = url(); * Template process function for theme_wysiwyg_dialog_page().
// @todo Would a breadcrumb make sense / possible at all? *
// $variables['breadcrumb'] = theme('breadcrumb', drupal_get_breadcrumb()); * @see wysiwyg_dialog()
$variables['head'] = drupal_get_html_head(); * @see wysiwyg-dialog-page.tpl.php
$variables['help'] = theme('help'); * @see template_process_page()
$variables['language'] = $GLOBALS['language']; */
$variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr'; function template_process_wysiwyg_dialog_page(&$variables) {
$variables['messages'] = $variables['show_messages'] ? theme('status_messages') : ''; template_process_page($variables);
$variables['site_name'] = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : '');
$variables['css'] = drupal_add_css();
$variables['styles'] = drupal_get_css();
$variables['scripts'] = drupal_get_js();
$variables['tabs'] = theme('menu_local_tasks');
$variables['title'] = drupal_get_title();
// Closure should be filled last.
$variables['closure'] = theme('closure');
} }

View File

@ -9,9 +9,9 @@ configure = admin/config/content/wysiwyg
files[] = wysiwyg.module files[] = wysiwyg.module
files[] = tests/wysiwyg.test files[] = tests/wysiwyg.test
; Information added by drupal.org packaging script on 2011-06-19 ; Information added by drupal.org packaging script on 2012-10-02
version = "7.x-2.1" version = "7.x-2.2"
core = "7.x" core = "7.x"
project = "wysiwyg" project = "wysiwyg"
datestamp = "1308450722" datestamp = "1349213776"

View File

@ -30,6 +30,7 @@ function wysiwyg_schema() {
'description' => 'Configuration settings for the editor.', 'description' => 'Configuration settings for the editor.',
'type' => 'text', 'type' => 'text',
'size' => 'normal', 'size' => 'normal',
'serialize' => TRUE,
), ),
), ),
'primary key' => array('format'), 'primary key' => array('format'),

View File

@ -11,7 +11,6 @@ Drupal.wysiwygInit = function() {
if (/KDE/.test(navigator.vendor)) { if (/KDE/.test(navigator.vendor)) {
return; return;
} }
jQuery.each(Drupal.wysiwyg.editor.init, function(editor) { jQuery.each(Drupal.wysiwyg.editor.init, function(editor) {
// Clone, so original settings are not overwritten. // Clone, so original settings are not overwritten.
this(jQuery.extend(true, {}, Drupal.settings.wysiwyg.configs[editor])); this(jQuery.extend(true, {}, Drupal.settings.wysiwyg.configs[editor]));
@ -38,13 +37,13 @@ Drupal.wysiwygInit = function() {
* A DOM element, supplied by Drupal.attachBehaviors(). * A DOM element, supplied by Drupal.attachBehaviors().
*/ */
Drupal.behaviors.attachWysiwyg = { Drupal.behaviors.attachWysiwyg = {
attach: function(context, settings) { attach: function (context, settings) {
// This breaks in Konqueror. Prevent it from running. // This breaks in Konqueror. Prevent it from running.
if (/KDE/.test(navigator.vendor)) { if (/KDE/.test(navigator.vendor)) {
return; return;
} }
$('.wysiwyg', context).once('wysiwyg', function() { $('.wysiwyg', context).once('wysiwyg', function () {
if (!this.id || typeof Drupal.settings.wysiwyg.triggers[this.id] === 'undefined') { if (!this.id || typeof Drupal.settings.wysiwyg.triggers[this.id] === 'undefined') {
return; return;
} }
@ -76,9 +75,27 @@ Drupal.behaviors.attachWysiwyg = {
if (event.isDefaultPrevented()) { if (event.isDefaultPrevented()) {
return; return;
} }
Drupal.wysiwygDetach(context, params[format]); Drupal.wysiwygDetach(context, params[format], 'serialize');
}); });
}); });
},
detach: function (context, settings, trigger) {
var wysiwygs;
// The 'serialize' trigger indicates that we should simply update the
// underlying element with the new text, without destroying the editor.
if (trigger == 'serialize') {
// Removing the wysiwyg-processed class guarantees that the editor will
// be reattached. Only do this if we're planning to destroy the editor.
wysiwygs = $('.wysiwyg-processed', context);
}
else {
wysiwygs = $('.wysiwyg', context).removeOnce('wysiwyg');
}
wysiwygs.each(function () {
var params = Drupal.settings.wysiwyg.triggers[this.id];
Drupal.wysiwygDetach(context, params, trigger);
});
} }
}; };
@ -136,11 +153,20 @@ Drupal.wysiwygAttach = function(context, params) {
* A DOM element, supplied by Drupal.attachBehaviors(). * A DOM element, supplied by Drupal.attachBehaviors().
* @param params * @param params
* An object containing input format parameters. * An object containing input format parameters.
* @param trigger
* A string describing what is causing the editor to be detached.
*
* @see Drupal.detachBehaviors
*/ */
Drupal.wysiwygDetach = function(context, params) { Drupal.wysiwygDetach = function (context, params, trigger) {
// Do not attempt to detach an unknown editor instance (Ajax).
if (typeof Drupal.wysiwyg.instances[params.field] == 'undefined') {
return;
}
trigger = trigger || 'unload';
var editor = Drupal.wysiwyg.instances[params.field].editor; var editor = Drupal.wysiwyg.instances[params.field].editor;
if (jQuery.isFunction(Drupal.wysiwyg.editor.detach[editor])) { if (jQuery.isFunction(Drupal.wysiwyg.editor.detach[editor])) {
Drupal.wysiwyg.editor.detach[editor](context, params); Drupal.wysiwyg.editor.detach[editor](context, params, trigger);
} }
}; };
@ -187,6 +213,7 @@ Drupal.wysiwyg.toggleWysiwyg = function (event) {
Drupal.wysiwyg.editor.attach.none(context, params); Drupal.wysiwyg.editor.attach.none(context, params);
Drupal.wysiwyg.instances[params.field] = Drupal.wysiwyg.editor.instance.none; Drupal.wysiwyg.instances[params.field] = Drupal.wysiwyg.editor.instance.none;
Drupal.wysiwyg.instances[params.field].editor = 'none'; Drupal.wysiwyg.instances[params.field].editor = 'none';
Drupal.wysiwyg.instances[params.field].field = params.field;
$(this).html(Drupal.settings.wysiwyg.enable).blur(); $(this).html(Drupal.settings.wysiwyg.enable).blur();
} }
else { else {
@ -234,4 +261,9 @@ Drupal.wysiwyg.getParams = function(element, params) {
*/ */
Drupal.wysiwygInit(); Drupal.wysiwygInit();
// Respond to CTools detach behaviors event.
$(document).bind('CToolsDetachBehaviors', function(event, context) {
Drupal.behaviors.attachWysiwyg.detach(context, {}, 'unload');
});
})(jQuery); })(jQuery);

View File

@ -79,9 +79,11 @@ function wysiwyg_menu() {
'type' => MENU_LOCAL_TASK, 'type' => MENU_LOCAL_TASK,
'weight' => 10, 'weight' => 10,
); );
// @see wysiwyg_dialog()
$items['wysiwyg/%'] = array( $items['wysiwyg/%'] = array(
'page callback' => 'wysiwyg_dialog', 'page callback' => 'wysiwyg_dialog',
'page arguments' => array(1), 'page arguments' => array(1),
'delivery callback' => 'wysiwyg_deliver_dialog_page',
'access arguments' => array('access content'), 'access arguments' => array('access content'),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'file' => 'wysiwyg.dialog.inc', 'file' => 'wysiwyg.dialog.inc',
@ -89,6 +91,19 @@ function wysiwyg_menu() {
return $items; return $items;
} }
/**
* Implements hook_element_info().
*/
function wysiwyg_element_info() {
// @see wysiwyg_dialog()
$types['wysiwyg_dialog_page'] = array(
'#theme' => 'wysiwyg_dialog_page',
'#theme_wrappers' => array('html'),
'#show_messages' => TRUE,
);
return $types;
}
/** /**
* Implementation of hook_theme(). * Implementation of hook_theme().
* *
@ -103,8 +118,9 @@ function wysiwyg_theme() {
'wysiwyg_admin_button_table' => array( 'wysiwyg_admin_button_table' => array(
'render element' => 'form', 'render element' => 'form',
), ),
// @see wysiwyg_dialog()
'wysiwyg_dialog_page' => array( 'wysiwyg_dialog_page' => array(
'variables' => array('content' => NULL, 'show_messages' => TRUE), 'render element' => 'page',
'file' => 'wysiwyg.dialog.inc', 'file' => 'wysiwyg.dialog.inc',
'template' => 'wysiwyg-dialog-page', 'template' => 'wysiwyg-dialog-page',
), ),
@ -117,7 +133,7 @@ function wysiwyg_theme() {
function wysiwyg_help($path, $arg) { function wysiwyg_help($path, $arg) {
switch ($path) { switch ($path) {
case 'admin/config/content/wysiwyg': case 'admin/config/content/wysiwyg':
$output = '<p>' . t('A Wysiwyg profile is associated with an input format. A Wysiwyg profile defines which client-side editor is loaded with a particular input format, what buttons or themes are enabled for the editor, how the editor is displayed, and a few other editor-specific functions.') . '</p>'; $output = '<p>' . t('A Wysiwyg profile is associated with a text format. A Wysiwyg profile defines which client-side editor is loaded with a particular text format, what buttons or themes are enabled for the editor, how the editor is displayed, and a few other editor-specific functions.') . '</p>';
return $output; return $output;
} }
} }
@ -286,6 +302,7 @@ function wysiwyg_get_profile($format) {
function wysiwyg_load_editor($profile) { function wysiwyg_load_editor($profile) {
static $settings_added; static $settings_added;
static $loaded = array(); static $loaded = array();
$path = drupal_get_path('module', 'wysiwyg');
$name = $profile->editor; $name = $profile->editor;
// Library files must be loaded only once. // Library files must be loaded only once.
@ -293,6 +310,13 @@ function wysiwyg_load_editor($profile) {
// Load editor. // Load editor.
$editor = wysiwyg_get_editor($name); $editor = wysiwyg_get_editor($name);
if ($editor) { if ($editor) {
$default_library_options = array(
'type' => 'file',
'scope' => 'header',
'defer' => FALSE,
'cache' => TRUE,
'preprocess' => TRUE,
);
// Determine library files to load. // Determine library files to load.
// @todo Allow to configure the library/execMode to use. // @todo Allow to configure the library/execMode to use.
if (isset($profile->settings['library']) && isset($editor['libraries'][$profile->settings['library']])) { if (isset($profile->settings['library']) && isset($editor['libraries'][$profile->settings['library']])) {
@ -305,9 +329,33 @@ function wysiwyg_load_editor($profile) {
$files = array_shift($editor['libraries']); $files = array_shift($editor['libraries']);
$files = $files['files']; $files = $files['files'];
} }
// Check whether the editor requires an initialization script.
if (!empty($editor['init callback'])) {
$init = $editor['init callback']($editor, $library, $profile);
if (!empty($init)) {
// Build a file for each of the editors to hold the init scripts.
// @todo Aggregate all initialization scripts into one file.
$uri = 'public://js/wysiwyg/wysiwyg_' . $name . '_' . drupal_hash_base64($init) . '.js';
$init_exists = file_exists($uri);
if (!$init_exists) {
$js_path = dirname($uri);
file_prepare_directory($js_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
}
// Attempt to create the file, or fall back to an inline script (which
// will not work in Ajax calls).
if (!$init_exists && !file_unmanaged_save_data($init, $uri, FILE_EXISTS_REPLACE)) {
drupal_add_js($init, array('type' => 'inline') + $default_library_options);
}
else {
drupal_add_js(file_create_url($uri), $default_library_options);
}
}
}
foreach ($files as $file => $options) { foreach ($files as $file => $options) {
if (is_array($options)) { if (is_array($options)) {
$options += array('type' => 'file', 'scope' => 'header', 'defer' => FALSE, 'cache' => TRUE, 'preprocess' => TRUE); $options += $default_library_options;
drupal_add_js($editor['library path'] . '/' . $file, $options); drupal_add_js($editor['library path'] . '/' . $file, $options);
} }
else { else {
@ -335,17 +383,6 @@ function wysiwyg_load_editor($profile) {
foreach ($files as $file) { foreach ($files as $file) {
drupal_add_css($editor['css path'] . '/' . $file); drupal_add_css($editor['css path'] . '/' . $file);
} }
drupal_add_js(array('wysiwyg' => array(
'configs' => array($editor['name'] => array('global' => array(
// @todo Move into (global) editor settings.
// If JS compression is enabled, at least TinyMCE is unable to determine
// its own base path and exec mode since it can't find the script name.
'editorBasePath' => base_path() . $editor['library path'],
'execMode' => $library,
))),
)), 'setting');
$loaded[$name] = TRUE; $loaded[$name] = TRUE;
} }
else { else {
@ -362,7 +399,6 @@ function wysiwyg_load_editor($profile) {
'enable' => t('Enable rich-text'), 'enable' => t('Enable rich-text'),
)), 'setting'); )), 'setting');
$path = drupal_get_path('module', 'wysiwyg');
// Initialize our namespaces in the *header* to do not force editor // Initialize our namespaces in the *header* to do not force editor
// integration scripts to check and define Drupal.wysiwyg on its own. // integration scripts to check and define Drupal.wysiwyg on its own.
drupal_add_js($path . '/wysiwyg.init.js', array('group' => JS_LIBRARY)); drupal_add_js($path . '/wysiwyg.init.js', array('group' => JS_LIBRARY));
@ -619,7 +655,10 @@ function wysiwyg_get_css() {
$files = array(); $files = array();
foreach (drupal_add_css() as $filepath => $info) { foreach (drupal_add_css() as $filepath => $info) {
if ($info['group'] >= CSS_THEME && $info['media'] != 'print') { if ($info['group'] >= CSS_THEME && $info['media'] != 'print') {
if (file_exists($filepath)) { if ($info['type'] == 'external') {
$files[] = $filepath;
}
elseif (file_exists($filepath)) {
$files[] = base_path() . $filepath; $files[] = base_path() . $filepath;
} }
} }
@ -809,6 +848,7 @@ function wysiwyg_get_all_editors() {
'libraries' => array(), 'libraries' => array(),
'version callback' => NULL, 'version callback' => NULL,
'themes callback' => NULL, 'themes callback' => NULL,
'settings form callback' => NULL,
'settings callback' => NULL, 'settings callback' => NULL,
'plugin callback' => NULL, 'plugin callback' => NULL,
'plugin settings callback' => NULL, 'plugin settings callback' => NULL,
@ -1077,3 +1117,19 @@ function _wysiwyg_process_include($module, $identifier, $path, $hook) {
/** /**
* @} End of "defgroup wysiwyg_api". * @} End of "defgroup wysiwyg_api".
*/ */
/**
* Implements hook_features_api().
*/
function wysiwyg_features_api() {
return array(
'wysiwyg' => array(
'name' => t('Wysiwyg profiles'),
'default_hook' => 'wysiwyg_default_profiles',
'default_file' => FEATURES_DEFAULTS_INCLUDED,
'feature_source' => TRUE,
'file' => drupal_get_path('module', 'wysiwyg') . '/wysiwyg.features.inc',
),
);
}