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
---------------------------
#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

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,
Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
verbatim copies of this license document, but changing it is not allowed.
Preamble
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
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 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 General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
When we speak of free software, we are referring to freedom, not price. Our
General Public Licenses are designed to make sure that you have the
freedom to distribute copies of free software (and charge for this service if
you wish), that you receive source code or can get it if you want it, that you
can change the software or use pieces of it in new free programs; and that
you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
To protect your rights, we need to make restrictions that forbid anyone to
deny you these rights or to ask you to surrender the rights. These restrictions
translate to certain responsibilities for you if you distribute copies of the
software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
For example, if you distribute copies of such a program, whether gratis or for
a fee, you must give the recipients all the rights that you have. You must make
sure that they, too, receive or can get the source code. And you must show
them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
We protect your rights with two steps: (1) copyright the software, and (2)
offer you this license which gives you legal permission to copy, distribute
and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Also, for each author's protection and ours, we want to make certain that
everyone understands that there is no warranty for this free software. If the
software is modified by someone else and passed on, we want its recipients
to know that what they have is not the original, so that any problems
introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
Finally, any free program is threatened constantly by software patents. We
wish to avoid the danger that redistributors of a free program will individually
obtain patent licenses, in effect making the program proprietary. To prevent
this, we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
The precise terms and conditions for copying, distribution and modification
follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
0. This License applies to any program or other work which contains a notice
placed by the copyright holder saying it may be distributed under the terms
of this General Public License. The "Program", below, refers to any such
program or work, and a "work based on the Program" means either the
Program or any derivative work under copyright law: that is to say, a work
containing the Program or a portion of it, either verbatim or with
modifications and/or translated into another language. (Hereinafter, translation
is included without limitation in the term "modification".) Each licensee is
addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
Activities other than copying, distribution and modification are not covered
by this License; they are outside its scope. The act of running the Program is
not restricted, and the output from the Program is covered only if its contents
constitute a work based on the Program (independent of having been made
by running the Program). Whether that is true depends on what the Program
does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this License
and to the absence of any warranty; and give any other recipients of the
Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
You may charge a fee for the physical act of transferring a copy, and you
may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
2. You may modify your copy or copies of the Program or any portion of it,
thus forming a work based on the Program, and copy and distribute such
modifications or work under the terms of Section 1 above, provided that you
also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
a) You must cause the modified files to carry prominent notices stating that
you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
b) You must cause any work that you distribute or publish, that in whole or in
part contains or is derived from the Program or any part thereof, to be
licensed as a whole at no charge to all third parties under the terms of this
License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
c) If the modified program normally reads commands interactively when run,
you must cause it, when started running for such interactive use in the most
ordinary way, to print or display an announcement including an appropriate
copyright notice and a notice that there is no warranty (or else, saying that
you provide a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this License.
(Exception: if the Program itself is interactive but does not normally print such
an announcement, your work based on the Program is not required to print
an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
These requirements apply to the modified work as a whole. If identifiable
sections of that work are not derived from the Program, and can be
reasonably considered independent and separate works in themselves, then
this License, and its terms, do not apply to those sections when you distribute
them as separate works. But when you distribute the same sections as part
of a whole which is a work based on the Program, the distribution of the
whole must be on the terms of this License, whose permissions for other
licensees extend to the entire whole, and thus to each and every part
regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to
work written entirely by you; rather, the intent is to exercise the right to
control the distribution of derivative or collective works based on the
Program.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of a
storage or distribution medium does not bring the other work under the scope
of this License.
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under
Section 2) in object code or executable form under the terms of Sections 1
and 2 above provided that you also do one of the following:
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source
code, which must be distributed under the terms of Sections 1 and 2 above
on a medium customarily used for software interchange; or,
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give
any third party, for a charge no more than your cost of physically performing
source distribution, a complete machine-readable copy of the corresponding
source code, to be distributed under the terms of Sections 1 and 2 above on
a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute
corresponding source code. (This alternative is allowed only for
noncommercial distribution and only if you received the program in object
code or executable form with such an offer, in accord with Subsection b
above.)
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source code
means all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation and
installation of the executable. However, as a special exception, the source
code distributed need not include anything that is normally distributed (in
either source or binary form) with the major components (compiler, kernel,
and so on) of the operating system on which the executable runs, unless that
component itself accompanies the executable.
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering access to
copy from a designated place, then offering equivalent access to copy the
source code from the same place counts as distribution of the source code,
even though third parties are not compelled to copy the source along with the
object code.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as
expressly provided under this License. Any attempt otherwise to copy,
modify, sublicense or distribute the Program is void, and will automatically
terminate your rights under this License. However, parties who have received
copies, or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it.
However, nothing else grants you permission to modify or distribute the
Program or its derivative works. These actions are prohibited by law if you
do not accept this License. Therefore, by modifying or distributing the
Program (or any work based on the Program), you indicate your acceptance
of this License to do so, and all its terms and conditions for copying,
distributing or modifying the Program or works based on it.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original
licensor to copy, distribute or modify the Program subject to these terms and
conditions. You may not impose any further restrictions on the recipients'
exercise of the rights granted herein. You are not responsible for enforcing
compliance by third parties to this License.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues), conditions
are imposed on you (whether by court order, agreement or otherwise) that
contradict the conditions of this License, they do not excuse you from the
conditions of this License. If you cannot distribute so as to satisfy
simultaneously your obligations under this License and any other pertinent
obligations, then as a consequence you may not distribute the Program at all.
For example, if a patent license would not permit royalty-free redistribution
of the Program by all those who receive copies directly or indirectly through
you, then the only way you could satisfy both it and this License would be to
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply and
the section as a whole is intended to apply in other circumstances.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any patents or
other property right claims or to contest validity of any such claims; this
section has the sole purpose of protecting the integrity of the free software
distribution system, which is implemented by public license practices. Many
people have made generous contributions to the wide range of software
distributed through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing to
distribute software through any other system and a licensee cannot impose
that choice.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to be a
consequence of the rest of this License.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain
countries either by patents or by copyrighted interfaces, the original copyright
holder who places the Program under this License may add an explicit
geographical distribution limitation excluding those countries, so that
distribution is permitted only in or among countries not thus excluded. In such
case, this License incorporates the limitation as if written in the body of this
License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will be
similar in spirit to the present version, but may differ in detail to address new
problems or concerns.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies
a version number of this License which applies to it and "any later version",
you have the option of following the terms and conditions either of that
version or of any later version published by the Free Software Foundation. If
the Program does not specify a version number of this License, you may
choose any version ever published by the Free Software Foundation.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free programs
whose distribution conditions are different, write to the author to ask for
permission. For software which is copyrighted by the Free Software
Foundation, write to the Free Software Foundation; we sometimes make
exceptions for this. Our decision will be guided by the two goals of
preserving the free status of all derivatives of our free software and of
promoting the sharing and reuse of software generally.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
NECESSARY SERVICING, REPAIR OR CORRECTION.
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OR INABILITY TO USE THE
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
OR DATA BEING RENDERED INACCURATE OR LOSSES
SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
THE POSSIBILITY OF SUCH DAMAGES.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
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 --
* 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,
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',
'themes callback' => 'wysiwyg_ckeditor_themes',
'settings form callback' => 'wysiwyg_ckeditor_settings_form',
'init callback' => 'wysiwyg_ckeditor_init',
'settings callback' => 'wysiwyg_ckeditor_settings',
'plugin callback' => 'wysiwyg_ckeditor_plugins',
'plugin settings callback' => 'wysiwyg_ckeditor_plugin_settings',
@ -48,6 +51,13 @@ function wysiwyg_ckeditor_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.
*
@ -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.
*
@ -127,8 +200,7 @@ function wysiwyg_ckeditor_themes($editor, $profile) {
*/
function wysiwyg_ckeditor_settings($editor, $config, $theme) {
$settings = array(
'baseHref' => $GLOBALS['base_url'] . '/',
'width' => '100%',
'width' => 'auto',
// For better compatibility with smaller textareas.
'resize_minWidth' => 450,
'height' => 420,
@ -167,7 +239,7 @@ function wysiwyg_ckeditor_settings($editor, $config, $theme) {
$settings['contentsCss'] = reset(wysiwyg_get_css());
}
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 {
@ -175,16 +247,25 @@ function wysiwyg_ckeditor_settings($editor, $config, $theme) {
$settings['contentsCss'] = wysiwyg_get_css();
}
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'])) {
$settings['language'] = $config['language'];
}
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'];
}
if (isset($config['toolbar_loc'])) {
@ -240,6 +321,51 @@ function wysiwyg_ckeditor_settings($editor, $config, $theme) {
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.
*/
@ -294,6 +420,7 @@ function wysiwyg_ckeditor_plugins($editor) {
'Bold' => t('Bold'), 'Italic' => t('Italic'), 'Underline' => t('Underline'),
'Strike' => t('Strike-through'),
'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'),
'Outdent' => t('Outdent'), 'Indent' => t('Indent'),
'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', '<')) {
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', '<')) {
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') {
$settings['EditorAreaCSS'] = implode(',', wysiwyg_get_css());
}
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['EditorAreaCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme()));
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$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.
CKEDITOR.config.customConfig = '';
var $drupalToolbar = $('#toolbar', Drupal.overlayChild ? window.parent.document : document);
settings.on = {
instanceReady: function(ev) {
var editor = ev.editor;
@ -125,6 +131,19 @@ Drupal.wysiwyg.editor.attach.ckeditor = function(context, params, settings) {
focus: function(ev) {
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
* 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') {
var instance = CKEDITOR.instances[params.field];
if (instance) {
instance.destroy();
instance[method]();
}
}
else {
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.
return content;
},
insert: function(content) {
content = this.prepareContent(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.
*/
Drupal.wysiwyg.editor.detach.fckeditor = function(context, params) {
Drupal.wysiwyg.editor.detach.fckeditor = function (context, params, trigger) {
var instances = [];
if (typeof params != 'undefined' && typeof FCKeditorAPI != 'undefined') {
var instance = FCKeditorAPI.GetInstance(params.field);
@ -36,6 +36,11 @@ Drupal.wysiwyg.editor.detach.fckeditor = function(context, params) {
for (var instanceName in instances) {
var instance = instances[instanceName];
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
// event handler needs to be removed to prevent data loss (in IE).
// 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);
// @see FCK.InsertHtml(), FCK.InsertElement()
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.
*/

View File

@ -11,15 +11,33 @@ Drupal.wysiwyg.editor.attach.jwysiwyg = function(context, params, settings) {
/**
* 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 editor = $field.data('wysiwyg');
if (typeof editor != 'undefined') {
editor.saveContent();
editor.element.remove();
if (trigger != 'serialize') {
editor.element.remove();
}
}
$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);

View File

@ -17,7 +17,10 @@ Drupal.wysiwyg.editor.attach.markitup = function(context, params, settings) {
/**
* 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') {
$('#' + 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);

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.
*/
Drupal.wysiwyg.editor.detach.nicedit = function(context, params) {
Drupal.wysiwyg.editor.detach.nicedit = function (context, params, trigger) {
if (typeof params != 'undefined') {
var instance = nicEditors.findEditor(params.field);
if (instance) {
instance.ne.removeInstance(params.field);
instance.ne.removePanel();
if (trigger == 'serialize') {
instance.saveContent();
}
else {
instance.ne.removeInstance(params.field);
instance.ne.removePanel();
}
}
}
else {
@ -43,10 +48,17 @@ Drupal.wysiwyg.editor.detach.nicedit = function(context, params) {
// Save contents of all editors back into textareas.
var instances = nicEditors.editors[e].nicInstances;
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.
nicEditors.editors[e].nicInstances = [];
if (trigger != 'serialize') {
nicEditors.editors[e].nicInstances = [];
}
}
}
};
@ -62,7 +74,7 @@ Drupal.wysiwyg.editor.instance.nicedit = {
// IE.
if (document.selection) {
editingArea.focus();
sel.createRange().text = content;
sel.createRange().pasteHTML(content);
}
else {
// Convert selection to a range.
@ -89,6 +101,14 @@ Drupal.wysiwyg.editor.instance.nicedit = {
// Only fragment children are inserted.
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) {
var $wrapper = $('#' + params.field).parents('.form-textarea-wrapper:first');
$wrapper.addClass('resizable');
if (Drupal.behaviors.textarea.attach) {
if (Drupal.behaviors.textarea) {
Drupal.behaviors.textarea.attach();
}
}
@ -26,6 +26,9 @@ Drupal.wysiwyg.editor.attach.none = function(context, params, settings) {
/**
* Detach a single or all editors.
*
* The editor syncs its contents back to the original field before its instance
* is removed.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @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,
* all editors should be detached and saved, so they can be submitted in
* 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) {
if (typeof params != 'undefined') {
Drupal.wysiwyg.editor.detach.none = function (context, params, trigger) {
if (typeof params != 'undefined' && (trigger != 'serialize')) {
var $wrapper = $('#' + params.field).parents('.form-textarea-wrapper:first');
$wrapper.removeOnce('textarea').removeClass('.resizable-textarea')
.find('.grippie').remove();
@ -65,6 +77,14 @@ Drupal.wysiwyg.editor.instance.none = {
else {
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($) {
// 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.
*/
@ -45,24 +58,84 @@ Drupal.wysiwyg.editor.attach.openwysiwyg = function(context, params, settings) {
/**
* 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') {
var instance = WYSIWYG.config[params.field];
if (typeof instance != 'undefined') {
WYSIWYG.updateTextArea(params.field);
jQuery('#wysiwyg_div_' + params.field).remove();
delete instance;
if (trigger != 'serialize') {
jQuery('#wysiwyg_div_' + params.field).remove();
delete instance;
}
}
if (trigger != 'serialize') {
jQuery('#' + params.field).show();
}
jQuery('#' + params.field).show();
}
else {
jQuery.each(WYSIWYG.config, function(field) {
WYSIWYG.updateTextArea(field);
jQuery('#wysiwyg_div_' + field).remove();
delete this;
jQuery('#' + field).show();
if (trigger != 'serialize') {
jQuery('#wysiwyg_div_' + field).remove();
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);

View File

@ -10,18 +10,8 @@
* An object containing editor settings for each input format.
*/
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.
for (var format in settings) {
if (format == 'global') {
continue;
}
tinyMCE.init(settings[format]);
if (Drupal.settings.wysiwyg.plugins[format]) {
// 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.
*/
Drupal.wysiwyg.editor.detach.tinymce = function(context, params) {
Drupal.wysiwyg.editor.detach.tinymce = function (context, params, trigger) {
if (typeof params != 'undefined') {
tinyMCE.removeMCEControl(tinyMCE.getEditorId(params.field));
$('#' + params.field).removeAttr('style');

View File

@ -11,19 +11,21 @@
* An object containing editor settings for each input format.
*/
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');
// Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
var $drupalToolbar = $('#toolbar', Drupal.overlayChild ? window.parent.document : document);
tinyMCE.onAddEditor.add(function (mgr, ed) {
if (ed.id == 'mce_fullscreen') {
$drupalToolbar.hide();
}
});
tinyMCE.onRemoveEditor.add(function (mgr, ed) {
if (ed.id == 'mce_fullscreen') {
$drupalToolbar.show();
}
});
// Initialize editor configurations.
for (var format in settings) {
if (format == 'global') {
continue;
};
tinyMCE.init(settings[format]);
if (Drupal.settings.wysiwyg.plugins[format]) {
// Load native external plugins.
// 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) {
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).
ed.onPostRender.add(function (ed) {
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.
*/
Drupal.wysiwyg.editor.detach.tinymce = function(context, params) {
Drupal.wysiwyg.editor.detach.tinymce = function (context, params, trigger) {
if (typeof params != 'undefined') {
var instance = tinyMCE.get(params.field);
if (instance) {
instance.save();
instance.remove();
if (trigger != 'serialize') {
instance.remove();
}
}
}
else {
// Save contents of all editors back into textareas.
tinyMCE.triggerSave();
// Remove all editor instances.
for (var instance in tinyMCE.editors) {
tinyMCE.editors[instance].remove();
if (trigger != 'serialize') {
// Remove all editor instances.
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.
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') {
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);
}
});
// Detach: Replace HTML representations with plain text.
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') {
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) {
var instanceId = this.isFullscreen() ? 'mce_fullscreen' : this.field;
var instanceId = this.getInstanceId();
var editor = tinyMCE.get(instanceId);
editor.windowManager.open({
file: dialog.url + '/' + instanceId,
@ -186,8 +196,7 @@ Drupal.wysiwyg.editor.instance.tinymce = {
},
closeDialog: function(dialog) {
var instanceId = this.isFullscreen() ? 'mce_fullscreen' : this.field;
var editor = tinyMCE.get(instanceId);
var editor = tinyMCE.get(this.getInstanceId());
editor.windowManager.close(dialog);
},
@ -222,13 +231,25 @@ Drupal.wysiwyg.editor.instance.tinymce = {
insert: function(content) {
content = this.prepareContent(content);
var instanceId = this.isFullscreen() ? 'mce_fullscreen' : this.field;
tinyMCE.execInstanceCommand(instanceId, 'mceInsertContent', false, content);
tinyMCE.execInstanceCommand(this.getInstanceId(), '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() {
// TinyMCE creates a completely new instance for fullscreen mode.
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.
makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all'));
// Whizzywig fails to detect and set initial textarea contents.
var instance = $('#whizzy' + params.field).get(0);
if (instance) {
instance.contentWindow.document.body.innerHTML = tidyD($field.val());
}
$('#whizzy' + params.field).contents().find('body').html(tidyD($field.val()));
};
/**
* 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 id = whizzies[index];
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();
}
var id = whizzies[index], $field = $('#' + id), instance = Drupal.wysiwyg.instances[id];
// 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.
$('#' + id + '-whizzywig').remove();
whizzies.splice(index, 1);
// Restore original textarea styling.
var originalValues = Drupal.wysiwyg.instances[id];
$field.removeAttr('style');
$field.attr('style', originalValues.originalStyle);
$field.removeAttr('style').attr('style', instance.originalStyle);
};
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);

View File

@ -29,42 +29,31 @@ Drupal.wysiwyg.editor.attach.whizzywig = function(context, params, settings) {
// Attach editor.
makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all'));
// Whizzywig fails to detect and set initial textarea contents.
var instance = $('#whizzy' + params.field).get(0);
if (instance) {
instance.contentWindow.document.body.innerHTML = tidyD($field.val());
}
$('#whizzy' + params.field).contents().find('body').html(tidyD($field.val()));
};
/**
* 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 id = whizzies[index];
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();
}
var id = whizzies[index], $field = $('#' + id), instance = Drupal.wysiwyg.instances[id];
// 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.
$container = $('#CONTAINER' + id);
var $container = $('#CONTAINER' + id);
$field.insertBefore($container);
// Remove editor instance.
$container.remove();
whizzies.splice(index, 1);
// Restore original textarea styling.
var originalValues = Drupal.wysiwyg.instances[id];
$field.removeAttr('style');
$field.attr('style', originalValues.originalStyle);
$field.removeAttr('style').attr('style', instance.originalStyle);
}
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);

View File

@ -71,41 +71,28 @@ Drupal.wysiwyg.editor.attach.whizzywig = function(context, params, settings) {
// Attach editor.
makeWhizzyWig(params.field, (settings.buttons ? settings.buttons : 'all'));
// Whizzywig fails to detect and set initial textarea contents.
var instance = $('#whizzy' + params.field).get(0);
if (instance) {
instance.contentWindow.document.body.innerHTML = tidyD($field.val());
}
$('#whizzy' + params.field).contents().find('body').html(tidyD($field.val()));
};
/**
* 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 id = whizzies[index];
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);
var id = whizzies[index], $field = $('#' + id), instance = Drupal.wysiwyg.instances[id];
// Save contents of editor back into textarea.
$field.val(window.get_xhtml ? get_xhtml(body) : body.innerHTML);
$field.val($field.val().replace(location.href + '#', '#'));
$field.val(instance.getContent());
// If the editor is just being serialized (not detached), our work is done.
if (trigger == 'serialize') {
return;
}
// Remove editor instance.
$('#' + id + '-whizzywig').remove();
whizzies.splice(index, 1);
// Restore original textarea styling.
var originalValues = Drupal.wysiwyg.instances[id];
$field.removeAttr('style');
$field.attr('style', originalValues.originalStyle);
$field.removeAttr('style').attr('style', instance.originalStyle);
};
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);

View File

@ -19,37 +19,55 @@ Drupal.wysiwyg.editor.attach.wymeditor = function (context, params, settings) {
/**
* 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') {
var $field = $('#' + params.field);
var index = $field.data(WYMeditor.WYM_INDEX);
if (typeof index != 'undefined') {
var instance = WYMeditor.INSTANCES[index];
instance.update();
$(instance._box).remove();
$(instance._element).show();
delete instance;
if (trigger != 'serialize') {
$(instance._box).remove();
$(instance._element).show();
delete instance;
}
}
if (trigger != 'serialize') {
$field.show();
}
$field.show();
}
else {
jQuery.each(WYMeditor.INSTANCES, function () {
this.update();
$(this._box).remove();
$(this._element).show();
delete this;
if (trigger != 'serialize') {
$(this._box).remove();
$(this._element).show();
delete this;
}
});
}
};
Drupal.wysiwyg.editor.instance.wymeditor = {
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 index = $field.data(WYMeditor.WYM_INDEX);
if (typeof index != 'undefined') {
var instance = WYMeditor.INSTANCES[index];
instance.insert(content);
return WYMeditor.INSTANCES[index];
}
return null;
}
};

118
editors/js/yui.js vendored
View File

@ -2,12 +2,70 @@
/**
* 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) {
// Apply 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.
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();
};
@ -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.
*/
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') {
var instance = YAHOO.widget.EditorInfo.getEditorById(params.field);
var instance = YAHOO.widget.EditorInfo._instances[params.field];
if (instance) {
instance.destroy();
instance[method]();
if (method == 'destroy') {
delete YAHOO.widget.EditorInfo._instances[params.field];
}
}
}
else {
for (var e in YAHOO.widget.EditorInfo._instances) {
// Save contents of all editors back into textareas.
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);

View File

@ -77,13 +77,13 @@ function wysiwyg_nicedit_settings($editor, $config, $theme) {
// Add editor content stylesheet.
if (isset($config['css_setting'])) {
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)) {
$settings['externalCSS'] = base_path() . $css;
}
}
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['externalCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme()));
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$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') {
$settings['CSSFile'] = reset(wysiwyg_get_css());
}
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['CSSFile'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme()));
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$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',
'themes callback' => 'wysiwyg_tinymce_themes',
'init callback' => 'wysiwyg_tinymce_init',
'settings callback' => 'wysiwyg_tinymce_settings',
'plugin callback' => 'wysiwyg_tinymce_plugins',
'plugin settings callback' => 'wysiwyg_tinymce_plugin_settings',
@ -125,6 +126,40 @@ function wysiwyg_tinymce_themes($editor, $profile) {
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.
*
@ -181,6 +216,7 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) {
$settings['remove_linebreaks'] = $config['remove_linebreaks'];
}
if (isset($config['verify_html'])) {
// TinyMCE performs a type-agnostic comparison on this particular setting.
$settings['verify_html'] = (bool) $config['verify_html'];
}
@ -192,8 +228,8 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) {
if ($config['css_setting'] == 'theme') {
$settings['content_css'] = implode(',', wysiwyg_get_css());
}
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['content_css'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme()));
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$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;
}
// 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;
}
// 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;
}
// Add plain extensions.
else if ($type == 'extensions' && !empty($plugins[$plugin]['load'])) {
elseif ($type == 'extensions' && !empty($plugins[$plugin]['load'])) {
$settings['extensions'][$plugin] = 1;
}
// Allow plugins to add valid HTML elements.
@ -268,7 +304,7 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) {
$settings += array(
'theme_advanced_resize_horizontal' => 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_toolbar_location' => isset($config['toolbar_loc']) ? $config['toolbar_loc'] : 'top',
'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;
}
else if ($op == 'remove') {
elseif ($op == 'remove') {
if (strpos($name, '-') === 0) {
return substr($name, 1);
}
@ -386,6 +422,8 @@ function wysiwyg_tinymce_plugins($editor) {
'link' => t('Link'), 'unlink' => t('Unlink'), 'anchor' => t('Anchor'),
'image' => t('Image'),
'cleanup' => t('Clean-up'),
'formatselect' => t('Block format'), 'styleselect' => t('Styles'),
'fontselect' => t('Font'), 'fontsizeselect' => t('Font size'),
'forecolor' => t('Forecolor'), 'backcolor' => t('Backcolor'),
'sup' => t('Superscript'), 'sub' => t('Subscript'),
'blockquote' => t('Blockquote'), 'code' => t('Source code'),
@ -402,15 +440,15 @@ function wysiwyg_tinymce_plugins($editor) {
'path' => $editor['library path'] . '/plugins/advhr',
'buttons' => array('advhr' => t('Advanced horizontal rule')),
'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,
'load' => TRUE,
),
'advimage' => array(
'path' => $editor['library path'] . '/plugins/advimage',
'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]'),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage',
'extended_valid_elements' => array('img[src|alt|title|align|width|height|usemap|hspace|vspace|border|style|class|onmouseover|onmouseout|id|name|longdesc]'),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:advimage',
'internal' => TRUE,
'load' => TRUE,
),
@ -418,49 +456,42 @@ function wysiwyg_tinymce_plugins($editor) {
'path' => $editor['library path'] . '/plugins/advlink',
'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]'),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink',
'url' => 'http://www.tinymce.com/wiki.php/Plugin:advlink',
'internal' => TRUE,
'load' => TRUE,
),
'autosave' => array(
'path' => $editor['library path'] . '/plugins/autosave',
'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,
'load' => TRUE,
),
'contextmenu' => array(
'path' => $editor['library path'] . '/plugins/contextmenu',
'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,
'load' => TRUE,
),
'directionality' => array(
'path' => $editor['library path'] . '/plugins/directionality',
'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,
'load' => TRUE,
),
'emotions' => array(
'path' => $editor['library path'] . '/plugins/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,
'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(
'path' => $editor['library path'] . '/plugins/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,
'load' => TRUE,
),
@ -470,7 +501,7 @@ function wysiwyg_tinymce_plugins($editor) {
'options' => array(
'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,
'load' => TRUE,
),
@ -481,56 +512,56 @@ function wysiwyg_tinymce_plugins($editor) {
'plugin_insertdate_dateFormat' => '%Y-%m-%d',
'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,
'load' => TRUE,
),
'layer' => array(
'path' => $editor['library path'] . '/plugins/layer',
'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,
'load' => TRUE,
),
'paste' => array(
'path' => $editor['library path'] . '/plugins/paste',
'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,
'load' => TRUE,
),
'preview' => array(
'path' => $editor['library path'] . '/plugins/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,
'load' => TRUE,
),
'print' => array(
'path' => $editor['library path'] . '/plugins/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,
'load' => TRUE,
),
'searchreplace' => array(
'path' => $editor['library path'] . '/plugins/searchreplace',
'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,
'load' => TRUE,
),
'style' => array(
'path' => $editor['library path'] . '/plugins/style',
'buttons' => array('styleprops' => t('Style properties')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style',
'buttons' => array('styleprops' => t('Advanced CSS styles')),
'url' => 'http://www.tinymce.com/wiki.php/Plugin:style',
'internal' => TRUE,
'load' => TRUE,
),
'table' => array(
'path' => $editor['library path'] . '/plugins/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,
'load' => TRUE,
),
@ -540,7 +571,6 @@ function wysiwyg_tinymce_plugins($editor) {
'path' => $editor['library path'] . '/plugins/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]'),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/flash',
'internal' => TRUE,
'load' => TRUE,
);
@ -549,14 +579,14 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['media'] = array(
'path' => $editor['library path'] . '/plugins/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,
'load' => TRUE,
);
$plugins['xhtmlxtras'] = array(
'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')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras',
'url' => 'http://www.tinymce.com/wiki.php/Plugin:xhtmlxtras',
'internal' => TRUE,
'load' => TRUE,
);
@ -565,7 +595,7 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['bbcode'] = array(
'path' => $editor['library path'] . '/plugins/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,
'load' => TRUE,
);
@ -573,7 +603,6 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['safari'] = array(
'path' => $editor['library path'] . '/plugins/safari',
'extensions' => array('safari' => t('Safari compatibility')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/safari',
'internal' => TRUE,
'load' => TRUE,
);
@ -583,7 +612,7 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['autoresize'] = array(
'path' => $editor['library path'] . '/plugins/autoresize',
'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,
'load' => TRUE,
);
@ -592,7 +621,7 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['advlist'] = array(
'path' => $editor['library path'] . '/plugins/advlist',
'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,
'load' => TRUE,
);
@ -601,11 +630,24 @@ function wysiwyg_tinymce_plugins($editor) {
$plugins['wordcount'] = array(
'path' => $editor['library path'] . '/plugins/wordcount',
'extensions' => array('wordcount' => t('Word count')),
'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/wordcount',
'internal' => 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;
}

View File

@ -104,13 +104,13 @@ function wysiwyg_whizzywig_settings($editor, $config, $theme) {
// Add editor content stylesheet.
if (isset($config['css_setting'])) {
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)) {
$settings['externalCSS'] = base_path() . $css;
}
}
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['externalCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme()));
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$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 ($config['css_setting'] == 'theme') {
// 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'])) {
$settings['stylesheet'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme()));
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$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(
'buttons' => array(
'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'),
'Undo' => t('Undo'), 'Redo' => t('Redo'),
'CreateLink' => t('Link'), 'Unlink' => t('Unlink'),
@ -212,22 +213,22 @@ function wysiwyg_wymeditor_plugins($editor) {
*/
function _wysiwyg_wymeditor_button_info() {
return array(
'Bold' => array('title'=> 'Strong', 'css'=> 'wym_tools_strong'),
'Italic' => array('title'=> 'Emphasis', 'css'=> 'wym_tools_emphasis'),
'Superscript' => array('title'=> 'Superscript', 'css'=> 'wym_tools_superscript'),
'Subscript' => array('title'=> 'Subscript', 'css'=> 'wym_tools_subscript'),
'InsertOrderedList' => array('title'=> 'Ordered_List', 'css'=> 'wym_tools_ordered_list'),
'InsertUnorderedList' => array('title'=> 'Unordered_List', 'css'=> 'wym_tools_unordered_list'),
'Indent' => array('title'=> 'Indent', 'css'=> 'wym_tools_indent'),
'Outdent' => array('title'=> 'Outdent', 'css'=> 'wym_tools_outdent'),
'Undo' => array('title'=> 'Undo', 'css'=> 'wym_tools_undo'),
'Redo' => array('title'=> 'Redo', 'css'=> 'wym_tools_redo'),
'CreateLink' => array('title'=> 'Link', 'css'=> 'wym_tools_link'),
'Unlink' => array('title'=> 'Unlink', 'css'=> 'wym_tools_unlink'),
'InsertImage' => array('title'=> 'Image', 'css'=> 'wym_tools_image'),
'InsertTable' => array('title'=> 'Table', 'css'=> 'wym_tools_table'),
'Paste' => array('title'=> 'Paste_From_Word', 'css'=> 'wym_tools_paste'),
'ToggleHtml' => array('title'=> 'HTML', 'css'=> 'wym_tools_html'),
'Preview' => array('title'=> 'Preview', 'css'=> 'wym_tools_preview'),
'Bold' => array('title' => 'Strong', 'css' => 'wym_tools_strong'),
'Italic' => array('title' => 'Emphasis', 'css' => 'wym_tools_emphasis'),
'Superscript' => array('title' => 'Superscript', 'css' => 'wym_tools_superscript'),
'Subscript' => array('title' => 'Subscript', 'css' => 'wym_tools_subscript'),
'InsertOrderedList' => array('title' => 'Ordered_List', 'css' => 'wym_tools_ordered_list'),
'InsertUnorderedList' => array('title' => 'Unordered_List', 'css' => 'wym_tools_unordered_list'),
'Indent' => array('title' => 'Indent', 'css' => 'wym_tools_indent'),
'Outdent' => array('title' => 'Outdent', 'css' => 'wym_tools_outdent'),
'Undo' => array('title' => 'Undo', 'css' => 'wym_tools_undo'),
'Redo' => array('title' => 'Redo', 'css' => 'wym_tools_redo'),
'CreateLink' => array('title' => 'Link', 'css' => 'wym_tools_link'),
'Unlink' => array('title' => 'Unlink', 'css' => 'wym_tools_unlink'),
'InsertImage' => array('title' => 'Image', 'css' => 'wym_tools_image'),
'InsertTable' => array('title' => 'Table', 'css' => 'wym_tools_table'),
'Paste' => array('title' => 'Paste_From_Word', 'css' => 'wym_tools_paste'),
'ToggleHtml' => array('title' => 'HTML', 'css' => 'wym_tools_html'),
'Preview' => array('title' => 'Preview', 'css' => 'wym_tools_preview'),
);
}

View File

@ -45,6 +45,14 @@ function wysiwyg_yui_editor() {
'load callback' => 'wysiwyg_yui_load',
'settings callback' => 'wysiwyg_yui_settings',
'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(
'2.7.0' => array(
'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(
array('text' => 'Arial', 'checked' => TRUE),
array('text' => 'Arial Black'),
@ -202,8 +210,8 @@ function wysiwyg_yui_settings($editor, $config, $theme) {
if ($config['css_setting'] == 'theme') {
$settings['extracss'] = wysiwyg_get_css();
}
else if ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$settings['extracss'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme()));
elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) {
$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']);
}
// 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;
if (!isset($plugins)) {
// @todo Invoke all enabled plugins, not just internals.
$plugins = wysiwyg_yui_plugins($editor);
$plugins = wysiwyg_get_plugins($editor['name']);
}
// Return a simple separator.
@ -269,6 +276,41 @@ function wysiwyg_yui_button_setting($editor, $plugin, $button, $extra = array())
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().
*/

View File

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

View File

@ -5,3 +5,46 @@
* 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
* Theme template 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()
* Theme implementation to display a single Wysiwyg (plugin) 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="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 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>
<?php print $messages; ?>
</div>
</div>
</div>
<?php print $closure; ?>
</body>
</html>
<div id="main-wrapper"><div id="main" class="clearfix">
<div id="content" class="column"><div class="section">
<a id="main-content"></a>
<?php print render($title_prefix); ?>
<?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;" />' : '';
}
$title = (isset($meta['url']) ? l($title, $meta['url'], array('target' => '_blank')) : $title);
$title = (!empty($icon) ? $icon . ' ' . $title : $title);
$title = (!empty($icon) ? $icon . ' ' . check_plain($title) : check_plain($title));
$form['buttons'][$name][$button] = array(
'#type' => 'checkbox',
'#title' => $title,
'#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) {
$form['buttons'][$name][$extension] = array(
'#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,
'#description' => isset($meta['url']) ? l($meta['url'], $meta['url']) : NULL,
);
}
}
@ -299,6 +300,19 @@ function wysiwyg_profile_form($form, &$form_state, $profile) {
'#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;
}
@ -363,14 +377,11 @@ function theme_wysiwyg_admin_button_table($variables) {
// Split checkboxes into rows with 3 columns.
$total = count($buttons);
$rows = array();
for ($i = 0; $i < $total; $i++) {
for ($i = 0; $i < $total; $i += 3) {
$row = array();
$row[] = array('data' => $buttons[$i]);
if (isset($buttons[++$i])) {
$row[] = array('data' => $buttons[$i]);
}
if (isset($buttons[++$i])) {
$row[] = array('data' => $buttons[$i]);
$row_buttons = array_slice($buttons, $i, 3) + array_fill(0, 3, array());
foreach ($row_buttons as $row_button) {
$row[] = array('data' => $row_button);
}
$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('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;
$count--;
}
@ -457,9 +473,20 @@ function wysiwyg_profile_overview($form, &$form_state) {
// Only display editor selection for associated input formats to avoid
// confusion about disabled selection.
if (isset($profiles[$id]) && !empty($profiles[$id]->editor)) {
$editor_name = $profiles[$id]->editor;
$installed = !empty($editors[$editor_name]['installed']);
$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 {
$form['formats'][$id]['editor'] = array(
@ -494,17 +521,28 @@ function theme_wysiwyg_profile_overview($variables) {
if (!isset($form['formats'])) {
return;
}
$editors = wysiwyg_get_all_editors();
$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();
foreach (element_children($form['formats']) as $item) {
$format = &$form['formats'][$item];
$rows[] = array(
drupal_render($format['name']),
drupal_render($format['editor']),
isset($format['edit']) ? drupal_render($format['edit']) : '',
isset($format['delete']) ? drupal_render($format['delete']) : '',
$row = array(
'data' => array(
drupal_render($format['name']),
drupal_render($format['editor']),
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));
$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)));
$form_state['redirect'] = 'admin/config/content/wysiwyg';
}

View File

@ -172,6 +172,83 @@ function hook_INCLUDE_plugin() {
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.
*

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) {
$plugins = wysiwyg_get_all_plugins();
@ -27,7 +88,74 @@ function wysiwyg_dialog($plugin, $instance) {
);
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-page.tpl.php
* @see template_preprocess()
* @see template_preprocess_page()
*/
function template_preprocess_wysiwyg_dialog_page(&$variables) {
// Construct page title
$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();
// @todo Would a breadcrumb make sense / possible at all?
// $variables['breadcrumb'] = theme('breadcrumb', drupal_get_breadcrumb());
$variables['head'] = drupal_get_html_head();
$variables['help'] = theme('help');
$variables['language'] = $GLOBALS['language'];
$variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr';
$variables['messages'] = $variables['show_messages'] ? theme('status_messages') : '';
$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');
template_preprocess_page($variables);
}
/**
* Template process function for theme_wysiwyg_dialog_page().
*
* @see wysiwyg_dialog()
* @see wysiwyg-dialog-page.tpl.php
* @see template_process_page()
*/
function template_process_wysiwyg_dialog_page(&$variables) {
template_process_page($variables);
}

View File

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

View File

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

View File

@ -11,7 +11,6 @@ Drupal.wysiwygInit = function() {
if (/KDE/.test(navigator.vendor)) {
return;
}
jQuery.each(Drupal.wysiwyg.editor.init, function(editor) {
// Clone, so original settings are not overwritten.
this(jQuery.extend(true, {}, Drupal.settings.wysiwyg.configs[editor]));
@ -38,13 +37,13 @@ Drupal.wysiwygInit = function() {
* A DOM element, supplied by Drupal.attachBehaviors().
*/
Drupal.behaviors.attachWysiwyg = {
attach: function(context, settings) {
attach: function (context, settings) {
// This breaks in Konqueror. Prevent it from running.
if (/KDE/.test(navigator.vendor)) {
return;
}
$('.wysiwyg', context).once('wysiwyg', function() {
$('.wysiwyg', context).once('wysiwyg', function () {
if (!this.id || typeof Drupal.settings.wysiwyg.triggers[this.id] === 'undefined') {
return;
}
@ -76,9 +75,27 @@ Drupal.behaviors.attachWysiwyg = {
if (event.isDefaultPrevented()) {
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().
* @param params
* 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;
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.instances[params.field] = Drupal.wysiwyg.editor.instance.none;
Drupal.wysiwyg.instances[params.field].editor = 'none';
Drupal.wysiwyg.instances[params.field].field = params.field;
$(this).html(Drupal.settings.wysiwyg.enable).blur();
}
else {
@ -234,4 +261,9 @@ Drupal.wysiwyg.getParams = function(element, params) {
*/
Drupal.wysiwygInit();
// Respond to CTools detach behaviors event.
$(document).bind('CToolsDetachBehaviors', function(event, context) {
Drupal.behaviors.attachWysiwyg.detach(context, {}, 'unload');
});
})(jQuery);

View File

@ -79,9 +79,11 @@ function wysiwyg_menu() {
'type' => MENU_LOCAL_TASK,
'weight' => 10,
);
// @see wysiwyg_dialog()
$items['wysiwyg/%'] = array(
'page callback' => 'wysiwyg_dialog',
'page arguments' => array(1),
'delivery callback' => 'wysiwyg_deliver_dialog_page',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
'file' => 'wysiwyg.dialog.inc',
@ -89,6 +91,19 @@ function wysiwyg_menu() {
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().
*
@ -103,8 +118,9 @@ function wysiwyg_theme() {
'wysiwyg_admin_button_table' => array(
'render element' => 'form',
),
// @see wysiwyg_dialog()
'wysiwyg_dialog_page' => array(
'variables' => array('content' => NULL, 'show_messages' => TRUE),
'render element' => 'page',
'file' => 'wysiwyg.dialog.inc',
'template' => 'wysiwyg-dialog-page',
),
@ -117,7 +133,7 @@ function wysiwyg_theme() {
function wysiwyg_help($path, $arg) {
switch ($path) {
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;
}
}
@ -286,6 +302,7 @@ function wysiwyg_get_profile($format) {
function wysiwyg_load_editor($profile) {
static $settings_added;
static $loaded = array();
$path = drupal_get_path('module', 'wysiwyg');
$name = $profile->editor;
// Library files must be loaded only once.
@ -293,6 +310,13 @@ function wysiwyg_load_editor($profile) {
// Load editor.
$editor = wysiwyg_get_editor($name);
if ($editor) {
$default_library_options = array(
'type' => 'file',
'scope' => 'header',
'defer' => FALSE,
'cache' => TRUE,
'preprocess' => TRUE,
);
// Determine library files to load.
// @todo Allow to configure the library/execMode to use.
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 = $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) {
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);
}
else {
@ -335,17 +383,6 @@ function wysiwyg_load_editor($profile) {
foreach ($files as $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;
}
else {
@ -362,7 +399,6 @@ function wysiwyg_load_editor($profile) {
'enable' => t('Enable rich-text'),
)), 'setting');
$path = drupal_get_path('module', 'wysiwyg');
// Initialize our namespaces in the *header* to do not force editor
// integration scripts to check and define Drupal.wysiwyg on its own.
drupal_add_js($path . '/wysiwyg.init.js', array('group' => JS_LIBRARY));
@ -619,7 +655,10 @@ function wysiwyg_get_css() {
$files = array();
foreach (drupal_add_css() as $filepath => $info) {
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;
}
}
@ -809,6 +848,7 @@ function wysiwyg_get_all_editors() {
'libraries' => array(),
'version callback' => NULL,
'themes callback' => NULL,
'settings form callback' => NULL,
'settings callback' => NULL,
'plugin callback' => NULL,
'plugin settings callback' => NULL,
@ -1077,3 +1117,19 @@ function _wysiwyg_process_include($module, $identifier, $path, $hook) {
/**
* @} 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',
),
);
}