Compare commits
No commits in common. '14b8c5f6e3eb9346b194212aad0b0dcdfc76e5f7' and 'e4ea789e9dd9da3fc0a91798972df32680590458' have entirely different histories.
14b8c5f6e3
...
e4ea789e9d
@ -1,85 +0,0 @@ |
|||||||
2010-03-xx Footnotes 7.x-2.5 |
|
||||||
|
|
||||||
- First Drupal 7 release. No major feature changes over 6.x-2.5. |
|
||||||
|
|
||||||
2010-12-31 Footnotes 2.5 |
|
||||||
|
|
||||||
Major features |
|
||||||
|
|
||||||
- Add new addon module: Footnotes with Views by AlexisWilke. [#939738] |
|
||||||
|
|
||||||
Smaller fixes |
|
||||||
|
|
||||||
- Remove "DEPRECATED" text from Better URL filter and instead have a small |
|
||||||
"Note" about it not being available in Footnotes 7.x-x.x. [#1002436] |
|
||||||
- Correctly ignore also a tag containing linebreak between the > and <. |
|
||||||
Fixes bug [#1002434] |
|
||||||
- Add textarea to ignored tags. Anything inside a textarea will be ignored. |
|
||||||
Bug [#974760] |
|
||||||
|
|
||||||
The intention is to branch a Drupal 7 version out of this release. |
|
||||||
|
|
||||||
2010-10-03 Footnotes 2.4 |
|
||||||
|
|
||||||
Major features |
|
||||||
|
|
||||||
- Add Footnotes Wysiwyg module with TinyMCE AND CKEditor support. |
|
||||||
This deprecates Footnotes TinyMCE module, which is kept around for backward |
|
||||||
compatibility. |
|
||||||
[#728642] |
|
||||||
- Add i18n support via Drupal.t() also to TinyMCE module. [#672034] |
|
||||||
- New feature (option): Collapse identical footnotes into one, as if using same |
|
||||||
value="". [#808214] |
|
||||||
- Implement [#728658] Highlight footnote when clicking the link. Add mention in |
|
||||||
README.txt how to change the highlight color if needed (Footnotes cannot know |
|
||||||
what is an appropriate color, I picked #eeeeee as the safest choice). |
|
||||||
|
|
||||||
Smaller fixes |
|
||||||
|
|
||||||
- Bug [#761390] |
|
||||||
Two small improper CSS names |
|
||||||
...was fixed by changing underscores to dashes in css selectors/classes. |
|
||||||
- Deprecate Better URL filter as it is committed to Drupal 7 now. [#296208] |
|
||||||
- Bug [#761664] |
|
||||||
Footnotes are double numbered when CSS is not used, such as in RSS feeds. |
|
||||||
(Due to using OL list) |
|
||||||
...was fixed by migrating to UL list. This is also appropriate since after |
|
||||||
introduction of the value="" parameter the footnotes needn't comprise an |
|
||||||
ordered list. |
|
||||||
|
|
||||||
|
|
||||||
2010-02-25 Footnotes 2.3 |
|
||||||
|
|
||||||
- Reset $used_values in _footnotes_replace_callback() after use. [#723446] |
|
||||||
|
|
||||||
2010-01-17 Footnotes 2.2 |
|
||||||
|
|
||||||
- Add TinyMCE support as a separate plugin tinymce_footnotes |
|
||||||
(thanks elgreg #464066) |
|
||||||
- Can have multiple references to same footnote in body by repeating value="" |
|
||||||
(#636808) |
|
||||||
Small fixes |
|
||||||
- Move translations from "po" to "translations" subdirectory. #430656 |
|
||||||
- Rename footnotes-alternative_layout.css due to typo in filename. |
|
||||||
- fix css: Use "ol.footnotes li" instead of "ol.footnotes" as selector for |
|
||||||
"list-style-type: none." Makes it stronger. |
|
||||||
- fix html: columns="" should be cols="" bug: #687244 |
|
||||||
|
|
||||||
2008-09-07 Footnotes 2.1 |
|
||||||
|
|
||||||
- Add "clear: both" to css of footnotes section. http://drupal.org/node/303828 |
|
||||||
|
|
||||||
2008-07-30 Footnotes 2.0 |
|
||||||
|
|
||||||
- Add support for using [fn]square brackets[/fn] (268026) |
|
||||||
- Change documentation to talk about [fn] by default, but <fn> is still |
|
||||||
supported |
|
||||||
- Add support for specifying "value" attribute. (emfabric 282104) |
|
||||||
- Mention http://drupal.org/node/279420 in known issues |
|
||||||
- Adding Better URL filter (fork from core). http://drupal.org/node/161217 |
|
||||||
- There appears to also be a French translation now. Thanks Beginner! |
|
||||||
(Japanese already done earlier.) |
|
||||||
- Fix bug where teaser might cut into the middle of a footnote: |
|
||||||
http://drupal.org/node/253326 |
|
||||||
- Start using the Drupal theme system, footnotes can now be themed by site |
|
||||||
admins (emfabric 221156) |
|
||||||
@ -1,674 +0,0 @@ |
|||||||
GNU GENERAL PUBLIC LICENSE |
|
||||||
Version 3, 29 June 2007 |
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
|
||||||
Everyone is permitted to copy and distribute verbatim copies |
|
||||||
of this license document, but changing it is not allowed. |
|
||||||
|
|
||||||
Preamble |
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for |
|
||||||
software and other kinds of works. |
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed |
|
||||||
to take away your freedom to share and change the works. By contrast, |
|
||||||
the GNU General Public License is intended to guarantee your freedom to |
|
||||||
share and change all versions of a program--to make sure it remains free |
|
||||||
software for all its users. We, the Free Software Foundation, use the |
|
||||||
GNU General Public License for most of our software; it applies also to |
|
||||||
any other work released this way by its authors. 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 |
|
||||||
them 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 prevent others from denying you |
|
||||||
these rights or asking you to surrender the rights. Therefore, you have |
|
||||||
certain responsibilities if you distribute copies of the software, or if |
|
||||||
you modify it: responsibilities to respect the freedom of others. |
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether |
|
||||||
gratis or for a fee, you must pass on to the recipients the same |
|
||||||
freedoms that you received. 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. |
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps: |
|
||||||
(1) assert copyright on the software, and (2) offer you this License |
|
||||||
giving you legal permission to copy, distribute and/or modify it. |
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains |
|
||||||
that there is no warranty for this free software. For both users' and |
|
||||||
authors' sake, the GPL requires that modified versions be marked as |
|
||||||
changed, so that their problems will not be attributed erroneously to |
|
||||||
authors of previous versions. |
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run |
|
||||||
modified versions of the software inside them, although the manufacturer |
|
||||||
can do so. This is fundamentally incompatible with the aim of |
|
||||||
protecting users' freedom to change the software. The systematic |
|
||||||
pattern of such abuse occurs in the area of products for individuals to |
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we |
|
||||||
have designed this version of the GPL to prohibit the practice for those |
|
||||||
products. If such problems arise substantially in other domains, we |
|
||||||
stand ready to extend this provision to those domains in future versions |
|
||||||
of the GPL, as needed to protect the freedom of users. |
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents. |
|
||||||
States should not allow patents to restrict development and use of |
|
||||||
software on general-purpose computers, but in those that do, we wish to |
|
||||||
avoid the special danger that patents applied to a free program could |
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that |
|
||||||
patents cannot be used to render the program non-free. |
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and |
|
||||||
modification follow. |
|
||||||
|
|
||||||
TERMS AND CONDITIONS |
|
||||||
|
|
||||||
0. Definitions. |
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License. |
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of |
|
||||||
works, such as semiconductor masks. |
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this |
|
||||||
License. Each licensee is addressed as "you". "Licensees" and |
|
||||||
"recipients" may be individuals or organizations. |
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work |
|
||||||
in a fashion requiring copyright permission, other than the making of an |
|
||||||
exact copy. The resulting work is called a "modified version" of the |
|
||||||
earlier work or a work "based on" the earlier work. |
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based |
|
||||||
on the Program. |
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without |
|
||||||
permission, would make you directly or secondarily liable for |
|
||||||
infringement under applicable copyright law, except executing it on a |
|
||||||
computer or modifying a private copy. Propagation includes copying, |
|
||||||
distribution (with or without modification), making available to the |
|
||||||
public, and in some countries other activities as well. |
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other |
|
||||||
parties to make or receive copies. Mere interaction with a user through |
|
||||||
a computer network, with no transfer of a copy, is not conveying. |
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices" |
|
||||||
to the extent that it includes a convenient and prominently visible |
|
||||||
feature that (1) displays an appropriate copyright notice, and (2) |
|
||||||
tells the user that there is no warranty for the work (except to the |
|
||||||
extent that warranties are provided), that licensees may convey the |
|
||||||
work under this License, and how to view a copy of this License. If |
|
||||||
the interface presents a list of user commands or options, such as a |
|
||||||
menu, a prominent item in the list meets this criterion. |
|
||||||
|
|
||||||
1. Source Code. |
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work |
|
||||||
for making modifications to it. "Object code" means any non-source |
|
||||||
form of a work. |
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official |
|
||||||
standard defined by a recognized standards body, or, in the case of |
|
||||||
interfaces specified for a particular programming language, one that |
|
||||||
is widely used among developers working in that language. |
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other |
|
||||||
than the work as a whole, that (a) is included in the normal form of |
|
||||||
packaging a Major Component, but which is not part of that Major |
|
||||||
Component, and (b) serves only to enable use of the work with that |
|
||||||
Major Component, or to implement a Standard Interface for which an |
|
||||||
implementation is available to the public in source code form. A |
|
||||||
"Major Component", in this context, means a major essential component |
|
||||||
(kernel, window system, and so on) of the specific operating system |
|
||||||
(if any) on which the executable work runs, or a compiler used to |
|
||||||
produce the work, or an object code interpreter used to run it. |
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all |
|
||||||
the source code needed to generate, install, and (for an executable |
|
||||||
work) run the object code and to modify the work, including scripts to |
|
||||||
control those activities. However, it does not include the work's |
|
||||||
System Libraries, or general-purpose tools or generally available free |
|
||||||
programs which are used unmodified in performing those activities but |
|
||||||
which are not part of the work. For example, Corresponding Source |
|
||||||
includes interface definition files associated with source files for |
|
||||||
the work, and the source code for shared libraries and dynamically |
|
||||||
linked subprograms that the work is specifically designed to require, |
|
||||||
such as by intimate data communication or control flow between those |
|
||||||
subprograms and other parts of the work. |
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users |
|
||||||
can regenerate automatically from other parts of the Corresponding |
|
||||||
Source. |
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that |
|
||||||
same work. |
|
||||||
|
|
||||||
2. Basic Permissions. |
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of |
|
||||||
copyright on the Program, and are irrevocable provided the stated |
|
||||||
conditions are met. This License explicitly affirms your unlimited |
|
||||||
permission to run the unmodified Program. The output from running a |
|
||||||
covered work is covered by this License only if the output, given its |
|
||||||
content, constitutes a covered work. This License acknowledges your |
|
||||||
rights of fair use or other equivalent, as provided by copyright law. |
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not |
|
||||||
convey, without conditions so long as your license otherwise remains |
|
||||||
in force. You may convey covered works to others for the sole purpose |
|
||||||
of having them make modifications exclusively for you, or provide you |
|
||||||
with facilities for running those works, provided that you comply with |
|
||||||
the terms of this License in conveying all material for which you do |
|
||||||
not control copyright. Those thus making or running the covered works |
|
||||||
for you must do so exclusively on your behalf, under your direction |
|
||||||
and control, on terms that prohibit them from making any copies of |
|
||||||
your copyrighted material outside their relationship with you. |
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under |
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10 |
|
||||||
makes it unnecessary. |
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological |
|
||||||
measure under any applicable law fulfilling obligations under article |
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or |
|
||||||
similar laws prohibiting or restricting circumvention of such |
|
||||||
measures. |
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid |
|
||||||
circumvention of technological measures to the extent such circumvention |
|
||||||
is effected by exercising rights under this License with respect to |
|
||||||
the covered work, and you disclaim any intention to limit operation or |
|
||||||
modification of the work as a means of enforcing, against the work's |
|
||||||
users, your or third parties' legal rights to forbid circumvention of |
|
||||||
technological measures. |
|
||||||
|
|
||||||
4. Conveying Verbatim Copies. |
|
||||||
|
|
||||||
You may convey 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; |
|
||||||
keep intact all notices stating that this License and any |
|
||||||
non-permissive terms added in accord with section 7 apply to the code; |
|
||||||
keep intact all notices of the absence of any warranty; and give all |
|
||||||
recipients a copy of this License along with the Program. |
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey, |
|
||||||
and you may offer support or warranty protection for a fee. |
|
||||||
|
|
||||||
5. Conveying Modified Source Versions. |
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to |
|
||||||
produce it from the Program, in the form of source code under the |
|
||||||
terms of section 4, provided that you also meet all of these conditions: |
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified |
|
||||||
it, and giving a relevant date. |
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is |
|
||||||
released under this License and any conditions added under section |
|
||||||
7. This requirement modifies the requirement in section 4 to |
|
||||||
"keep intact all notices". |
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this |
|
||||||
License to anyone who comes into possession of a copy. This |
|
||||||
License will therefore apply, along with any applicable section 7 |
|
||||||
additional terms, to the whole of the work, and all its parts, |
|
||||||
regardless of how they are packaged. This License gives no |
|
||||||
permission to license the work in any other way, but it does not |
|
||||||
invalidate such permission if you have separately received it. |
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display |
|
||||||
Appropriate Legal Notices; however, if the Program has interactive |
|
||||||
interfaces that do not display Appropriate Legal Notices, your |
|
||||||
work need not make them do so. |
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent |
|
||||||
works, which are not by their nature extensions of the covered work, |
|
||||||
and which are not combined with it such as to form a larger program, |
|
||||||
in or on a volume of a storage or distribution medium, is called an |
|
||||||
"aggregate" if the compilation and its resulting copyright are not |
|
||||||
used to limit the access or legal rights of the compilation's users |
|
||||||
beyond what the individual works permit. Inclusion of a covered work |
|
||||||
in an aggregate does not cause this License to apply to the other |
|
||||||
parts of the aggregate. |
|
||||||
|
|
||||||
6. Conveying Non-Source Forms. |
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms |
|
||||||
of sections 4 and 5, provided that you also convey the |
|
||||||
machine-readable Corresponding Source under the terms of this License, |
|
||||||
in one of these ways: |
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product |
|
||||||
(including a physical distribution medium), accompanied by the |
|
||||||
Corresponding Source fixed on a durable physical medium |
|
||||||
customarily used for software interchange. |
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product |
|
||||||
(including a physical distribution medium), accompanied by a |
|
||||||
written offer, valid for at least three years and valid for as |
|
||||||
long as you offer spare parts or customer support for that product |
|
||||||
model, to give anyone who possesses the object code either (1) a |
|
||||||
copy of the Corresponding Source for all the software in the |
|
||||||
product that is covered by this License, on a durable physical |
|
||||||
medium customarily used for software interchange, for a price no |
|
||||||
more than your reasonable cost of physically performing this |
|
||||||
conveying of source, or (2) access to copy the |
|
||||||
Corresponding Source from a network server at no charge. |
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the |
|
||||||
written offer to provide the Corresponding Source. This |
|
||||||
alternative is allowed only occasionally and noncommercially, and |
|
||||||
only if you received the object code with such an offer, in accord |
|
||||||
with subsection 6b. |
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated |
|
||||||
place (gratis or for a charge), and offer equivalent access to the |
|
||||||
Corresponding Source in the same way through the same place at no |
|
||||||
further charge. You need not require recipients to copy the |
|
||||||
Corresponding Source along with the object code. If the place to |
|
||||||
copy the object code is a network server, the Corresponding Source |
|
||||||
may be on a different server (operated by you or a third party) |
|
||||||
that supports equivalent copying facilities, provided you maintain |
|
||||||
clear directions next to the object code saying where to find the |
|
||||||
Corresponding Source. Regardless of what server hosts the |
|
||||||
Corresponding Source, you remain obligated to ensure that it is |
|
||||||
available for as long as needed to satisfy these requirements. |
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided |
|
||||||
you inform other peers where the object code and Corresponding |
|
||||||
Source of the work are being offered to the general public at no |
|
||||||
charge under subsection 6d. |
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded |
|
||||||
from the Corresponding Source as a System Library, need not be |
|
||||||
included in conveying the object code work. |
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any |
|
||||||
tangible personal property which is normally used for personal, family, |
|
||||||
or household purposes, or (2) anything designed or sold for incorporation |
|
||||||
into a dwelling. In determining whether a product is a consumer product, |
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular |
|
||||||
product received by a particular user, "normally used" refers to a |
|
||||||
typical or common use of that class of product, regardless of the status |
|
||||||
of the particular user or of the way in which the particular user |
|
||||||
actually uses, or expects or is expected to use, the product. A product |
|
||||||
is a consumer product regardless of whether the product has substantial |
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent |
|
||||||
the only significant mode of use of the product. |
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods, |
|
||||||
procedures, authorization keys, or other information required to install |
|
||||||
and execute modified versions of a covered work in that User Product from |
|
||||||
a modified version of its Corresponding Source. The information must |
|
||||||
suffice to ensure that the continued functioning of the modified object |
|
||||||
code is in no case prevented or interfered with solely because |
|
||||||
modification has been made. |
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or |
|
||||||
specifically for use in, a User Product, and the conveying occurs as |
|
||||||
part of a transaction in which the right of possession and use of the |
|
||||||
User Product is transferred to the recipient in perpetuity or for a |
|
||||||
fixed term (regardless of how the transaction is characterized), the |
|
||||||
Corresponding Source conveyed under this section must be accompanied |
|
||||||
by the Installation Information. But this requirement does not apply |
|
||||||
if neither you nor any third party retains the ability to install |
|
||||||
modified object code on the User Product (for example, the work has |
|
||||||
been installed in ROM). |
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a |
|
||||||
requirement to continue to provide support service, warranty, or updates |
|
||||||
for a work that has been modified or installed by the recipient, or for |
|
||||||
the User Product in which it has been modified or installed. Access to a |
|
||||||
network may be denied when the modification itself materially and |
|
||||||
adversely affects the operation of the network or violates the rules and |
|
||||||
protocols for communication across the network. |
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided, |
|
||||||
in accord with this section must be in a format that is publicly |
|
||||||
documented (and with an implementation available to the public in |
|
||||||
source code form), and must require no special password or key for |
|
||||||
unpacking, reading or copying. |
|
||||||
|
|
||||||
7. Additional Terms. |
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this |
|
||||||
License by making exceptions from one or more of its conditions. |
|
||||||
Additional permissions that are applicable to the entire Program shall |
|
||||||
be treated as though they were included in this License, to the extent |
|
||||||
that they are valid under applicable law. If additional permissions |
|
||||||
apply only to part of the Program, that part may be used separately |
|
||||||
under those permissions, but the entire Program remains governed by |
|
||||||
this License without regard to the additional permissions. |
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option |
|
||||||
remove any additional permissions from that copy, or from any part of |
|
||||||
it. (Additional permissions may be written to require their own |
|
||||||
removal in certain cases when you modify the work.) You may place |
|
||||||
additional permissions on material, added by you to a covered work, |
|
||||||
for which you have or can give appropriate copyright permission. |
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you |
|
||||||
add to a covered work, you may (if authorized by the copyright holders of |
|
||||||
that material) supplement the terms of this License with terms: |
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the |
|
||||||
terms of sections 15 and 16 of this License; or |
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or |
|
||||||
author attributions in that material or in the Appropriate Legal |
|
||||||
Notices displayed by works containing it; or |
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or |
|
||||||
requiring that modified versions of such material be marked in |
|
||||||
reasonable ways as different from the original version; or |
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or |
|
||||||
authors of the material; or |
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some |
|
||||||
trade names, trademarks, or service marks; or |
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that |
|
||||||
material by anyone who conveys the material (or modified versions of |
|
||||||
it) with contractual assumptions of liability to the recipient, for |
|
||||||
any liability that these contractual assumptions directly impose on |
|
||||||
those licensors and authors. |
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further |
|
||||||
restrictions" within the meaning of section 10. If the Program as you |
|
||||||
received it, or any part of it, contains a notice stating that it is |
|
||||||
governed by this License along with a term that is a further |
|
||||||
restriction, you may remove that term. If a license document contains |
|
||||||
a further restriction but permits relicensing or conveying under this |
|
||||||
License, you may add to a covered work material governed by the terms |
|
||||||
of that license document, provided that the further restriction does |
|
||||||
not survive such relicensing or conveying. |
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you |
|
||||||
must place, in the relevant source files, a statement of the |
|
||||||
additional terms that apply to those files, or a notice indicating |
|
||||||
where to find the applicable terms. |
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the |
|
||||||
form of a separately written license, or stated as exceptions; |
|
||||||
the above requirements apply either way. |
|
||||||
|
|
||||||
8. Termination. |
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly |
|
||||||
provided under this License. Any attempt otherwise to propagate or |
|
||||||
modify it is void, and will automatically terminate your rights under |
|
||||||
this License (including any patent licenses granted under the third |
|
||||||
paragraph of section 11). |
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your |
|
||||||
license from a particular copyright holder is reinstated (a) |
|
||||||
provisionally, unless and until the copyright holder explicitly and |
|
||||||
finally terminates your license, and (b) permanently, if the copyright |
|
||||||
holder fails to notify you of the violation by some reasonable means |
|
||||||
prior to 60 days after the cessation. |
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is |
|
||||||
reinstated permanently if the copyright holder notifies you of the |
|
||||||
violation by some reasonable means, this is the first time you have |
|
||||||
received notice of violation of this License (for any work) from that |
|
||||||
copyright holder, and you cure the violation prior to 30 days after |
|
||||||
your receipt of the notice. |
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the |
|
||||||
licenses of parties who have received copies or rights from you under |
|
||||||
this License. If your rights have been terminated and not permanently |
|
||||||
reinstated, you do not qualify to receive new licenses for the same |
|
||||||
material under section 10. |
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies. |
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or |
|
||||||
run a copy of the Program. Ancillary propagation of a covered work |
|
||||||
occurring solely as a consequence of using peer-to-peer transmission |
|
||||||
to receive a copy likewise does not require acceptance. However, |
|
||||||
nothing other than this License grants you permission to propagate or |
|
||||||
modify any covered work. These actions infringe copyright if you do |
|
||||||
not accept this License. Therefore, by modifying or propagating a |
|
||||||
covered work, you indicate your acceptance of this License to do so. |
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients. |
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically |
|
||||||
receives a license from the original licensors, to run, modify and |
|
||||||
propagate that work, subject to this License. You are not responsible |
|
||||||
for enforcing compliance by third parties with this License. |
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an |
|
||||||
organization, or substantially all assets of one, or subdividing an |
|
||||||
organization, or merging organizations. If propagation of a covered |
|
||||||
work results from an entity transaction, each party to that |
|
||||||
transaction who receives a copy of the work also receives whatever |
|
||||||
licenses to the work the party's predecessor in interest had or could |
|
||||||
give under the previous paragraph, plus a right to possession of the |
|
||||||
Corresponding Source of the work from the predecessor in interest, if |
|
||||||
the predecessor has it or can get it with reasonable efforts. |
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the |
|
||||||
rights granted or affirmed under this License. For example, you may |
|
||||||
not impose a license fee, royalty, or other charge for exercise of |
|
||||||
rights granted under this License, and you may not initiate litigation |
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that |
|
||||||
any patent claim is infringed by making, using, selling, offering for |
|
||||||
sale, or importing the Program or any portion of it. |
|
||||||
|
|
||||||
11. Patents. |
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this |
|
||||||
License of the Program or a work on which the Program is based. The |
|
||||||
work thus licensed is called the contributor's "contributor version". |
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims |
|
||||||
owned or controlled by the contributor, whether already acquired or |
|
||||||
hereafter acquired, that would be infringed by some manner, permitted |
|
||||||
by this License, of making, using, or selling its contributor version, |
|
||||||
but do not include claims that would be infringed only as a |
|
||||||
consequence of further modification of the contributor version. For |
|
||||||
purposes of this definition, "control" includes the right to grant |
|
||||||
patent sublicenses in a manner consistent with the requirements of |
|
||||||
this License. |
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free |
|
||||||
patent license under the contributor's essential patent claims, to |
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and |
|
||||||
propagate the contents of its contributor version. |
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express |
|
||||||
agreement or commitment, however denominated, not to enforce a patent |
|
||||||
(such as an express permission to practice a patent or covenant not to |
|
||||||
sue for patent infringement). To "grant" such a patent license to a |
|
||||||
party means to make such an agreement or commitment not to enforce a |
|
||||||
patent against the party. |
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license, |
|
||||||
and the Corresponding Source of the work is not available for anyone |
|
||||||
to copy, free of charge and under the terms of this License, through a |
|
||||||
publicly available network server or other readily accessible means, |
|
||||||
then you must either (1) cause the Corresponding Source to be so |
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the |
|
||||||
patent license for this particular work, or (3) arrange, in a manner |
|
||||||
consistent with the requirements of this License, to extend the patent |
|
||||||
license to downstream recipients. "Knowingly relying" means you have |
|
||||||
actual knowledge that, but for the patent license, your conveying the |
|
||||||
covered work in a country, or your recipient's use of the covered work |
|
||||||
in a country, would infringe one or more identifiable patents in that |
|
||||||
country that you have reason to believe are valid. |
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or |
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a |
|
||||||
covered work, and grant a patent license to some of the parties |
|
||||||
receiving the covered work authorizing them to use, propagate, modify |
|
||||||
or convey a specific copy of the covered work, then the patent license |
|
||||||
you grant is automatically extended to all recipients of the covered |
|
||||||
work and works based on it. |
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within |
|
||||||
the scope of its coverage, prohibits the exercise of, or is |
|
||||||
conditioned on the non-exercise of one or more of the rights that are |
|
||||||
specifically granted under this License. You may not convey a covered |
|
||||||
work if you are a party to an arrangement with a third party that is |
|
||||||
in the business of distributing software, under which you make payment |
|
||||||
to the third party based on the extent of your activity of conveying |
|
||||||
the work, and under which the third party grants, to any of the |
|
||||||
parties who would receive the covered work from you, a discriminatory |
|
||||||
patent license (a) in connection with copies of the covered work |
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily |
|
||||||
for and in connection with specific products or compilations that |
|
||||||
contain the covered work, unless you entered into that arrangement, |
|
||||||
or that patent license was granted, prior to 28 March 2007. |
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting |
|
||||||
any implied license or other defenses to infringement that may |
|
||||||
otherwise be available to you under applicable patent law. |
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom. |
|
||||||
|
|
||||||
If 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 convey a |
|
||||||
covered work so as to satisfy simultaneously your obligations under this |
|
||||||
License and any other pertinent obligations, then as a consequence you may |
|
||||||
not convey it at all. For example, if you agree to terms that obligate you |
|
||||||
to collect a royalty for further conveying from those to whom you convey |
|
||||||
the Program, the only way you could satisfy both those terms and this |
|
||||||
License would be to refrain entirely from conveying the Program. |
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License. |
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have |
|
||||||
permission to link or combine any covered work with a work licensed |
|
||||||
under version 3 of the GNU Affero General Public License into a single |
|
||||||
combined work, and to convey the resulting work. The terms of this |
|
||||||
License will continue to apply to the part which is the covered work, |
|
||||||
but the special requirements of the GNU Affero General Public License, |
|
||||||
section 13, concerning interaction through a network will apply to the |
|
||||||
combination as such. |
|
||||||
|
|
||||||
14. Revised Versions of this License. |
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of |
|
||||||
the GNU 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 that a certain numbered version of the GNU General |
|
||||||
Public License "or any later version" applies to it, you have the |
|
||||||
option of following the terms and conditions either of that numbered |
|
||||||
version or of any later version published by the Free Software |
|
||||||
Foundation. If the Program does not specify a version number of the |
|
||||||
GNU General Public License, you may choose any version ever published |
|
||||||
by the Free Software Foundation. |
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future |
|
||||||
versions of the GNU General Public License can be used, that proxy's |
|
||||||
public statement of acceptance of a version permanently authorizes you |
|
||||||
to choose that version for the Program. |
|
||||||
|
|
||||||
Later license versions may give you additional or different |
|
||||||
permissions. However, no additional obligations are imposed on any |
|
||||||
author or copyright holder as a result of your choosing to follow a |
|
||||||
later version. |
|
||||||
|
|
||||||
15. Disclaimer of Warranty. |
|
||||||
|
|
||||||
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. |
|
||||||
|
|
||||||
16. Limitation of Liability. |
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
|
||||||
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. |
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16. |
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided |
|
||||||
above cannot be given local legal effect according to their terms, |
|
||||||
reviewing courts shall apply local law that most closely approximates |
|
||||||
an absolute waiver of all civil liability in connection with the |
|
||||||
Program, unless a warranty or assumption of liability accompanies a |
|
||||||
copy of the Program in return for a fee. |
|
||||||
|
|
||||||
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 |
|
||||||
state 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 3 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, see <http://www.gnu.org/licenses/>. |
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail. |
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short |
|
||||||
notice like this when it starts in an interactive mode: |
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author> |
|
||||||
This program 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, your program's commands |
|
||||||
might be different; for a GUI interface, you would use an "about box". |
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school, |
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary. |
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see |
|
||||||
<http://www.gnu.org/licenses/>. |
|
||||||
|
|
||||||
The GNU 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. But first, please read |
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>. |
|
||||||
@ -1,19 +0,0 @@ |
|||||||
# Merged BibCite Footnotes module |
|
||||||
|
|
||||||
This package merges the original `bibcite_footnotes` module and the CKEditor 5-only `bibcite_footnotes_2` module back into a single Drupal module named `bibcite_footnotes`. |
|
||||||
|
|
||||||
## What changed |
|
||||||
|
|
||||||
- Kept the original `bibcite_footnotes` machine name. |
|
||||||
- Removed the hard dependency on `fakeobjects` from the main `.info.yml` so the module can be used on CKEditor 5 / Drupal 10+ sites. |
|
||||||
- Added `bibcite_footnotes.ckeditor5.yml` for CKEditor 5 toolbar integration. |
|
||||||
- Added the CKEditor 5 `footnote_picker` library and supporting CSS/JS from `bibcite_footnotes_2`. |
|
||||||
- Repointed CKEditor 5 library references from `bibcite_footnotes_2/...` to `bibcite_footnotes/...`. |
|
||||||
- Removed the duplicate/stale CKEditor 5 PHP plugin class and old raw `js/ckeditor5` plugin files to avoid competing CKEditor 5 plugin definitions. |
|
||||||
- Kept the CKEditor 4 plugin files/classes for older Drupal 9 / CKEditor 4 use. |
|
||||||
|
|
||||||
## Notes |
|
||||||
|
|
||||||
The optional `bibcite_footnotes_article_with_citations` submodule is still a CKEditor 4 example configuration because its installed editor config uses `editor: ckeditor` and the `reference_footnotes` CKEditor 4 toolbar button. |
|
||||||
|
|
||||||
On a CKEditor 5 site, enable the main module and add the `Footnote/Citation` button to the desired text format's CKEditor 5 toolbar. Make sure the text format allows the custom `<fn value page reference>` element and the `filter_reference_footnotes` filter is enabled. |
|
||||||
@ -1,100 +0,0 @@ |
|||||||
Bibcite Footnotes |
|
||||||
================= |
|
||||||
|
|
||||||
Contents |
|
||||||
-------- |
|
||||||
|
|
||||||
* Introduction |
|
||||||
* Installation |
|
||||||
* Use |
|
||||||
* Current Maintainers |
|
||||||
|
|
||||||
Introduction |
|
||||||
------------ |
|
||||||
|
|
||||||
Provides a CKEditor plugin that lets a user select from a list of citations which |
|
||||||
appear in a formatted list at the bottom of the text that contains endnotes |
|
||||||
and references. |
|
||||||
|
|
||||||
Installation |
|
||||||
------------ |
|
||||||
|
|
||||||
### Works Cited field |
|
||||||
|
|
||||||
1. Go to Administration > Structure > Content Types and edit the type that will include Reference Footnotes |
|
||||||
2. In the Manage Fields tab, press Add Field. |
|
||||||
3. In "Re-use an existing field" select "Entity reference: field_bibcite_fn_works_cited". |
|
||||||
4. Enter an appropriate label and press 'Save and continue'. |
|
||||||
5. On the next page select all the items in "Reference type" that should be available to choose from as footnotes. |
|
||||||
6. Customize the field under "Manage form display" and "Manage display", typically you'll want to |
|
||||||
place the Works Cited field directly under the Body field. See below for configuring with |
|
||||||
Inline Entity Form. |
|
||||||
7. In "Manage display", select "Rendered entity" in the Format drop-down for the Works Cited field. |
|
||||||
8. Press the Settings icon and under "View mode" choose "Citation" - a new view mode created |
|
||||||
by this module. |
|
||||||
|
|
||||||
#### Inline Enity Form |
|
||||||
|
|
||||||
It's recommended to also install [Inline Entity Form][1] which allowes a user to |
|
||||||
create new references directly in the node edit form. |
|
||||||
|
|
||||||
1. In "Entity Form Display", select ''Inline Entity Form - complex". |
|
||||||
2. Press the settings button in the rightmost column. |
|
||||||
3. Enabling "Allow users to add new reference entities" and |
|
||||||
"Allow users to add existing reference entities" is recommended. |
|
||||||
|
|
||||||
[1]: https://www.drupal.org/project/inline_entity_form |
|
||||||
|
|
||||||
### CKEditor filter and toolbar button |
|
||||||
|
|
||||||
1. Enable the module. |
|
||||||
2. Go to Administration > Configuration > Content authoring > Text formats and editors. |
|
||||||
3. Edit the text format you want to add Reference Footnotes to |
|
||||||
4. Enable the Reference Footnotes Filter |
|
||||||
5. Drag the Reference Footnotes button into the active buttons toolbar. |
|
||||||
6. Configure the options for the Reference Footnotes Filter. |
|
||||||
|
|
||||||
If the 'Allowed HTML tags' filter is enabled add these HTML tags to the allowed list: |
|
||||||
|
|
||||||
```html |
|
||||||
<a class href id> <div class id> <span class id> <ol class id type> |
|
||||||
<sup> <li class id> |
|
||||||
``` |
|
||||||
|
|
||||||
Use |
|
||||||
--- |
|
||||||
|
|
||||||
See the documentation for [Bibliography and Citation - Import][2] module for how to |
|
||||||
add citations exported from a citation management system like RefWorks or EndNote. |
|
||||||
|
|
||||||
[2]: https://www.drupal.org/project/bibcite |
|
||||||
|
|
||||||
### Adding a Works Cited item |
|
||||||
|
|
||||||
If Inline Entity Form is enabled, an author can create new citations or add references to |
|
||||||
previously-imported or created references directly with the 'Add new reference' and |
|
||||||
'Add existing reference' buttons. |
|
||||||
|
|
||||||
With Inline Entity Form, newly-added citations are immediately selectable in the |
|
||||||
Reference Footnotes dialog. |
|
||||||
|
|
||||||
If not using the inline entity form, you can select previously imported or created references |
|
||||||
|
|
||||||
When you edit the node again, and you click on the Reference Footnote editor toolbar button, |
|
||||||
a list of citations will be available to choose from. |
|
||||||
|
|
||||||
### Citation Formatting |
|
||||||
|
|
||||||
The Works Cited field will use the Default style selected in the |
|
||||||
Bibliography & Citation administration pages at Administration > Configuration > |
|
||||||
Bibliography & Citation > Settings in the Processing tab under Processor.' |
|
||||||
|
|
||||||
Current Maintainers |
|
||||||
------------------- |
|
||||||
|
|
||||||
* Alexander O'Neill (https://www.drupal.org/u/alxp) |
|
||||||
|
|
||||||
Sponsors |
|
||||||
-------- |
|
||||||
|
|
||||||
* This work is supported by the [University of Prince Edward Island Robertson Library](https://library.upei.ca). |
|
||||||
@ -1,57 +0,0 @@ |
|||||||
INTRODUCTION |
|
||||||
------------------ |
|
||||||
|
|
||||||
The Footnotes module is used to easily create automatically numbered footnote references in an article or post (such as a reference to a URL). |
|
||||||
|
|
||||||
* For a full description of the module, visit the project page: |
|
||||||
https://www.drupal.org/project/footnotes |
|
||||||
|
|
||||||
* To submit bug reports and feature suggestions, or track changes: |
|
||||||
https://www.drupal.org/project/issues/footnotes |
|
||||||
|
|
||||||
REQUIREMENTS |
|
||||||
------------------ |
|
||||||
|
|
||||||
The Footnote module for Drupal 8 requires the following modules and plugins: |
|
||||||
|
|
||||||
* FakeObjects (https://www.drupal.org/project/fakeobjects) |
|
||||||
* CKEditor plugin (http://ckeditor.com/addon/fakeobjects) |
|
||||||
|
|
||||||
INSTALLATION |
|
||||||
---------------- |
|
||||||
* Before you can use the FakeObjects module, you need to download the plugin from http://ckeditor.com/addon/fakeobjects and place it in /libraries/fakeobjects. |
|
||||||
|
|
||||||
* In all other steps, install the module as you would normally install a contributed Drupal module. Visit |
|
||||||
https://www.drupal.org/docs/8/extending-drupal-8/installing-drupal-8-modules for further information. |
|
||||||
|
|
||||||
CONFIGURATION |
|
||||||
------------------- |
|
||||||
* To use the footnotes filter in some input formats, go to Configuration -> |
|
||||||
Text formats. |
|
||||||
|
|
||||||
* For the Text formats you want to support footnotes markup, select configure and activate a suitable footnotes filter. |
|
||||||
|
|
||||||
* In the place where you want to add a footnote enclose the footnote text within an fn tag:<code>[fn]like this[/fn]</code>. By default, footnotes are placed at the end of the text. You can also use a <code>[footnotes]</code> or <code>[footnotes /]</code> tag to position it anywhere you want. |
|
||||||
|
|
||||||
* The filter will take the text within the tag and move it to a footnote at the |
|
||||||
bottom of the page. In it's place it will place a number which is also a link to |
|
||||||
the footnote. Footnotes supports both <code>[fn]square brackets[/fn]</code> and <code><fn>angle brackets</fn></code>. |
|
||||||
|
|
||||||
* You can also use a "value" attribute to a) set the numbering to start from the given value, or b) to set an arbitrary text string as label. |
|
||||||
|
|
||||||
Ex: |
|
||||||
|
|
||||||
[fn value="5"]This becomes footnote #5. Subsequent are #6, #7...[/fn] |
|
||||||
[fn value="*"]This footnote is assigned the label "*"[/fn] |
|
||||||
|
|
||||||
Using value="" you can have multiple references to the same footnote in the text body. |
|
||||||
|
|
||||||
[fn value="5"]This becomes footnote #5.[/fn] |
|
||||||
[fn value="5"]This is a reference to the same footnote #5, this text itself is discarded.[/fn] |
|
||||||
|
|
||||||
TROUBLESHOOTING & FAQ |
|
||||||
------------------------------ |
|
||||||
|
|
||||||
Q: When trying to install the Footnotes module, I get the message: Before you can use the FakeObjects module, you need to download the plugin from ckeditor.com and place it in /libraries/fakeobjects." |
|
||||||
|
|
||||||
A: To avoid this error message, please follow the guidelines in the Required modules and the Installation sections of this Readme file. Please mind that the Drupal 8.x-2.x branch of the Footnotes module only supports the CKEditor and does not support the TinyMCE. |
|
||||||
@ -1,75 +0,0 @@ |
|||||||
/* |
|
||||||
* CSS specific to Footnotes module. |
|
||||||
* |
|
||||||
* This is an alternative layout, it is not so nice but overcomes |
|
||||||
* the layout bugs on IE. http://drupal.org/node/166628 |
|
||||||
* To use this layout, just rename this file to footnotes.css. |
|
||||||
*/ |
|
||||||
|
|
||||||
/* Add empty space before footnotes and a black line on top. */ |
|
||||||
.footnotes { |
|
||||||
clear: both; |
|
||||||
margin-top: 4em; |
|
||||||
margin-bottom: 2em; |
|
||||||
border-top: 1px solid #000; |
|
||||||
} |
|
||||||
/* Make footnotes appear in a smaller font */ |
|
||||||
.footnotes { |
|
||||||
font-size: 0.9em; |
|
||||||
} |
|
||||||
/* |
|
||||||
Make the footnote a supertext^1 |
|
||||||
*/ |
|
||||||
.see-footnote { |
|
||||||
vertical-align: top; |
|
||||||
position: relative; |
|
||||||
top: -0.25em; |
|
||||||
font-size: 0.9em; |
|
||||||
} |
|
||||||
/* Hide the bullet of the UL list of footnotes */ |
|
||||||
|
|
||||||
ul.footnotes { |
|
||||||
list-style-type: none; |
|
||||||
margin-left: 0; |
|
||||||
padding-left: 0; |
|
||||||
} |
|
||||||
ul.footnotes li { |
|
||||||
margin-left: 0.5em; |
|
||||||
list-style-type: none; |
|
||||||
background: none; /* Garland theme sets a bullet via background image, this must be unset! See bug 861634 */ |
|
||||||
} |
|
||||||
.footnotes .footnote-label { |
|
||||||
vertical-align: top; |
|
||||||
position: relative; |
|
||||||
top: -0.35em; |
|
||||||
left: -0.35em; |
|
||||||
font-size: 0.8em; |
|
||||||
} |
|
||||||
/* Highlight the target footnote (or ref number, if a backlink was used) when user clicks a footnote. */ |
|
||||||
.see-footnote:target, |
|
||||||
.footnotes .footnote:target { |
|
||||||
background-color: #eee; |
|
||||||
} |
|
||||||
.see-footnote:target { |
|
||||||
border: solid 1px #aaa; |
|
||||||
} |
|
||||||
/* |
|
||||||
Make the multiple backlinks a supertext^1 |
|
||||||
*/ |
|
||||||
.footnotes .footnote-multi { |
|
||||||
vertical-align: top; |
|
||||||
position: relative; |
|
||||||
top: -0.25em; |
|
||||||
font-size: 0.75em; |
|
||||||
} |
|
||||||
/* |
|
||||||
* Textile Footnotes |
|
||||||
*/ |
|
||||||
/* First footnote */ |
|
||||||
#fn1 { |
|
||||||
border-top: 1px solid #000; |
|
||||||
margin-top: 3em; |
|
||||||
} |
|
||||||
.footnote { |
|
||||||
font-size: 0.9em; |
|
||||||
} |
|
||||||
@ -1,82 +0,0 @@ |
|||||||
/* |
|
||||||
* CSS specific to Footnotes module. |
|
||||||
* |
|
||||||
* Thanks to binford2k@lug.wsu.edu for this tip and drinkypoo |
|
||||||
* for the question leading up to it. http://drupal.org/node/80538 |
|
||||||
*/ |
|
||||||
|
|
||||||
/* Add empty space before footnotes and a black line on top. */ |
|
||||||
.footnotes { |
|
||||||
clear: both; |
|
||||||
margin-top: 4em; |
|
||||||
margin-bottom: 2em; |
|
||||||
border-top: 1px solid #000; |
|
||||||
} |
|
||||||
/* Make footnotes appear in a smaller font */ |
|
||||||
.footnotes { |
|
||||||
font-size: 0.9em; |
|
||||||
} |
|
||||||
/* |
|
||||||
Make the footnote a supertext^1 |
|
||||||
*/ |
|
||||||
.see-footnote { |
|
||||||
vertical-align: top; |
|
||||||
position: relative; |
|
||||||
top: -0.25em; |
|
||||||
font-size: 0.9em; |
|
||||||
} |
|
||||||
/* Hide the bullet of the UL list of footnotes */ |
|
||||||
|
|
||||||
ul.footnotes { |
|
||||||
list-style-type: none; |
|
||||||
margin-left: 0; |
|
||||||
padding-left: 0; |
|
||||||
} |
|
||||||
ul.footnotes li { |
|
||||||
margin-left: 2.5em; |
|
||||||
list-style-type: none; |
|
||||||
background: none; /* Garland theme sets a bullet via background image, this must be unset! See bug 861634 */ |
|
||||||
} |
|
||||||
/* Move the footnote number outside of the margin for footnote text (hanging indent) */ |
|
||||||
ul.footnotes { |
|
||||||
/* This is apparently very needed for the "position: absolute;" below to work correctly */ |
|
||||||
position: relative; |
|
||||||
} |
|
||||||
.footnotes .footnote-label { |
|
||||||
position: absolute; |
|
||||||
left: 0; |
|
||||||
z-index: 2; |
|
||||||
} |
|
||||||
/* Highlight the target footnote (or ref number, if a backlink was used) when user clicks a footnote. */ |
|
||||||
.see-footnote:target, |
|
||||||
.footnotes .footnote:target { |
|
||||||
background-color: #eee; |
|
||||||
} |
|
||||||
.see-footnote:target { |
|
||||||
border: solid 1px #aaa; |
|
||||||
} |
|
||||||
/* Note: This CSS has a minor bug on all versions of IE in that the footnote numbers |
|
||||||
are aligned with the absolute bottom of their space, thus being a couple of pixels |
|
||||||
lower than their corresponding line of text. IE5.5 has a serious bug in that the numbers |
|
||||||
are not shifted left at all, thus being garbled together with the start of their text. */ |
|
||||||
|
|
||||||
/* |
|
||||||
Make the multiple backlinks a supertext^1 |
|
||||||
*/ |
|
||||||
.footnotes .footnote-multi { |
|
||||||
vertical-align: top; |
|
||||||
position: relative; |
|
||||||
top: -0.25em; |
|
||||||
font-size: 0.75em; |
|
||||||
} |
|
||||||
/* |
|
||||||
* Textile Footnotes |
|
||||||
*/ |
|
||||||
/* First footnote */ |
|
||||||
#fn1 { |
|
||||||
border-top: 1px solid #000; |
|
||||||
margin-top: 3em; |
|
||||||
} |
|
||||||
.footnote { |
|
||||||
font-size: 0.9em; |
|
||||||
} |
|
||||||
@ -1,60 +0,0 @@ |
|||||||
/** |
|
||||||
* @file |
|
||||||
*/ |
|
||||||
|
|
||||||
function footnotesDialog(editor, isEdit) { |
|
||||||
return { |
|
||||||
title: Drupal.t("Footnotes Dialog"), |
|
||||||
minWidth: 500, |
|
||||||
minHeight: 50, |
|
||||||
contents: [ |
|
||||||
{ |
|
||||||
id: "info", |
|
||||||
label: Drupal.t("Add a footnote"), |
|
||||||
title: Drupal.t("Add a footnote"), |
|
||||||
elements: [ |
|
||||||
{ |
|
||||||
id: "footnote", |
|
||||||
type: "text", |
|
||||||
label: Drupal.t("Footnote text :"), |
|
||||||
setup(element) { |
|
||||||
if (isEdit) { |
|
||||||
this.setValue(element.getHtml()); |
|
||||||
} |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: "value", |
|
||||||
type: "text", |
|
||||||
label: Drupal.t("Value :"), |
|
||||||
setup(element) { |
|
||||||
if (isEdit) { |
|
||||||
this.setValue(element.getAttribute("value")); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
], |
|
||||||
onShow() { |
|
||||||
if (isEdit) { |
|
||||||
this.fakeObj = CKEDITOR.plugins.footnotes.getSelectedFootnote(editor); |
|
||||||
this.realObj = editor.restoreRealElement(this.fakeObj); |
|
||||||
} |
|
||||||
this.setupContent(this.realObj); |
|
||||||
}, |
|
||||||
onOk() { |
|
||||||
CKEDITOR.plugins.footnotes.createFootnote( |
|
||||||
editor, |
|
||||||
this.realObj, |
|
||||||
this.getValueOf("info", "footnote"), |
|
||||||
this.getValueOf("info", "value") |
|
||||||
); |
|
||||||
delete this.fakeObj; |
|
||||||
delete this.realObj; |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
CKEDITOR.dialog.add("createfootnotes", editor => footnotesDialog(editor)); |
|
||||||
CKEDITOR.dialog.add("editfootnotes", editor => footnotesDialog(editor, 1)); |
|
||||||
|
Before Width: | Height: | Size: 262 B |
|
Before Width: | Height: | Size: 263 B |
@ -1,151 +0,0 @@ |
|||||||
/** |
|
||||||
* @file |
|
||||||
* A CKeditor plugin to insert footnotes as in-place <fn> elements (consumed by Footnotes module in Drupal). |
|
||||||
* |
|
||||||
* This is a rather sophisticated plugin to show a dialog to insert |
|
||||||
* <fn> footnotes or edit existing ones. It produces and understands |
|
||||||
* the <fn>angle bracket</fn> variant and uses the fakeObjects API to |
|
||||||
* show a nice icon to the user, while producing proper <fn> tags when |
|
||||||
* the text is saved or View Source is pressed. |
|
||||||
* |
|
||||||
* If a text contains footnotes of the [fn]square bracket[/fn] variant, |
|
||||||
* they will be visible in the text and this plugin will not react to them. |
|
||||||
* |
|
||||||
* This plugin uses Drupal.t() to translate strings and will not as such |
|
||||||
* work outside of Drupal. (But removing those functions would be the only |
|
||||||
* change needed.) While being part of a Wysiwyg compatible module, it could |
|
||||||
* also be used together with the CKEditor module. |
|
||||||
* |
|
||||||
* Drupal Wysiwyg requirement: The first argument to CKEDITOR.plugins.add() |
|
||||||
* must be equal to the key used in $plugins[] in hook_wysiwyg_plugin(). |
|
||||||
*/ |
|
||||||
|
|
||||||
CKEDITOR.plugins.add("footnotes", { |
|
||||||
requires: ["fakeobjects", "dialog"], |
|
||||||
icons: "footnotes", |
|
||||||
onLoad() { |
|
||||||
const iconPath = `${window.location.origin + this.path}icons/fn_icon2.png`; |
|
||||||
CKEDITOR.addCss( |
|
||||||
`${".cke_footnote{background-image: url("}${CKEDITOR.getUrl( |
|
||||||
iconPath |
|
||||||
)});` +
|
|
||||||
`background - position: center center;` + |
|
||||||
`background - repeat: no - repeat;` + |
|
||||||
`width: 16px;` + |
|
||||||
`height: 16px;` + |
|
||||||
`}` |
|
||||||
); |
|
||||||
}, |
|
||||||
init(editor) { |
|
||||||
editor.addCommand( |
|
||||||
"createfootnotes", |
|
||||||
new CKEDITOR.dialogCommand("createfootnotes", { |
|
||||||
allowedContent: "fn[value]" |
|
||||||
}) |
|
||||||
); |
|
||||||
editor.addCommand( |
|
||||||
"editfootnotes", |
|
||||||
new CKEDITOR.dialogCommand("editfootnotes", { |
|
||||||
allowedContent: "fn[value]" |
|
||||||
}) |
|
||||||
); |
|
||||||
|
|
||||||
// Drupal Wysiwyg requirement: The first argument to editor.ui.addButton()
|
|
||||||
// must be equal to the key used in $plugins[<pluginName>]['buttons'][<key>]
|
|
||||||
// in hook_wysiwyg_plugin().
|
|
||||||
if (editor.ui.addButton) { |
|
||||||
editor.ui.addButton("footnotes", { |
|
||||||
label: Drupal.t("Add a footnote"), |
|
||||||
command: "createfootnotes", |
|
||||||
icon: "footnotes" |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
if (editor.addMenuItems) { |
|
||||||
editor.addMenuGroup("footnotes", 100); |
|
||||||
editor.addMenuItems({ |
|
||||||
footnotes: { |
|
||||||
label: Drupal.t("Edit footnote"), |
|
||||||
command: "editfootnotes", |
|
||||||
icon: "footnotes", |
|
||||||
group: "footnotes" |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
if (editor.contextMenu) { |
|
||||||
editor.contextMenu.addListener(element => { |
|
||||||
if (!element || element.data("cke-real-element-type") !== "fn") { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return { footnotes: CKEDITOR.TRISTATE_ON }; |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
editor.on("doubleclick", evt => { |
|
||||||
if (CKEDITOR.plugins.footnotes.getSelectedFootnote(editor)) { |
|
||||||
evt.data.dialog = "editfootnotes"; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
CKEDITOR.dialog.add("createfootnotes", `${this.path}dialogs/footnotes.js`); |
|
||||||
CKEDITOR.dialog.add("editfootnotes", `${this.path}dialogs/footnotes.js`); |
|
||||||
}, |
|
||||||
afterInit(editor) { |
|
||||||
const { dataProcessor } = editor; |
|
||||||
const { dataFilter } = dataProcessor; |
|
||||||
|
|
||||||
if (dataFilter) { |
|
||||||
dataFilter.addRules({ |
|
||||||
elements: { |
|
||||||
fn(element) { |
|
||||||
return editor.createFakeParserElement( |
|
||||||
element, |
|
||||||
"cke_footnote", |
|
||||||
"hiddenfield", |
|
||||||
false |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
CKEDITOR.plugins.footnotes = { |
|
||||||
createFootnote(editor, origElement, text, value) { |
|
||||||
let realElement; |
|
||||||
if (!origElement) { |
|
||||||
realElement = CKEDITOR.dom.element.createFromHtml("<fn></fn>"); |
|
||||||
} else { |
|
||||||
realElement = origElement; |
|
||||||
} |
|
||||||
|
|
||||||
if (text && text.length > 0) { |
|
||||||
realElement.setHtml(text); |
|
||||||
} |
|
||||||
if (value && value.length > 0) { |
|
||||||
realElement.setAttribute("value", value); |
|
||||||
} |
|
||||||
|
|
||||||
const fakeElement = editor.createFakeElement( |
|
||||||
realElement, |
|
||||||
"cke_footnote", |
|
||||||
"hiddenfield", |
|
||||||
false |
|
||||||
); |
|
||||||
editor.insertElement(fakeElement); |
|
||||||
}, |
|
||||||
|
|
||||||
getSelectedFootnote(editor) { |
|
||||||
const selection = editor.getSelection(); |
|
||||||
const element = selection.getSelectedElement(); |
|
||||||
const seltype = selection.getType(); |
|
||||||
|
|
||||||
if ( |
|
||||||
seltype === CKEDITOR.SELECTION_ELEMENT && |
|
||||||
element.data("cke-real-element-type") === "hiddenfield" |
|
||||||
) { |
|
||||||
return element; |
|
||||||
} |
|
||||||
} |
|
||||||
}; |
|
||||||
@ -1,14 +0,0 @@ |
|||||||
bibcite_footnotes_footnote_picker: |
|
||||||
ckeditor5: |
|
||||||
plugins: |
|
||||||
- footnotepicker2.FootnotePicker2 |
|
||||||
drupal: |
|
||||||
label: 'Footnote/Citation' |
|
||||||
library: bibcite_footnotes/footnote_picker |
|
||||||
admin_library: bibcite_footnotes/footnote_picker |
|
||||||
toolbar_items: |
|
||||||
footnotePicker2: |
|
||||||
label: 'Footnote' |
|
||||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path d="M6.5 4.5c-.6 0-1 .4-1 1v4.2c0 .6.4 1 1 1h.8v1.7H6.2c-.6 0-1 .4-1 1v.4h3.3c.6 0 1-.4 1-1V10c0-.5-.3-.9-.7-1.1.4-.3.7-.7.7-1.3V5.5c0-.6-.4-1-1-1H6.5z"/><path d="M11 6h7v1.4h-7V6zm0 3h7v1.4h-7V9zm0 3h5v1.4h-5V12z"/></svg>' |
|
||||||
elements: |
|
||||||
- <fn value page reference> |
|
||||||
@ -1,10 +0,0 @@ |
|||||||
name: 'BibCite Footnotes' |
|
||||||
type: module |
|
||||||
description: 'Inline footnote links for BibCite References with CKEditor 4 and CKEditor 5 support.' |
|
||||||
core_version_requirement: ^9.5 || ^10 || ^11 |
|
||||||
package: 'Bibliography & Citation' |
|
||||||
dependencies: |
|
||||||
- bibcite:bibcite |
|
||||||
- bibcite:bibcite_entity |
|
||||||
- drupal:editor |
|
||||||
- drupal:filter |
|
||||||
@ -1,29 +0,0 @@ |
|||||||
reference_footnote: |
|
||||||
version: VERSION |
|
||||||
css: |
|
||||||
theme: |
|
||||||
css/reference_footnote.css: {} |
|
||||||
dependencies: |
|
||||||
- core/jquery |
|
||||||
- core/drupalSettings |
|
||||||
|
|
||||||
replace_citations: |
|
||||||
version: VERSION |
|
||||||
js: |
|
||||||
js/replace_citations.js: {} |
|
||||||
dependencies: |
|
||||||
- core/jquery |
|
||||||
- core/drupalSettings |
|
||||||
|
|
||||||
footnote_picker: |
|
||||||
css: |
|
||||||
theme: |
|
||||||
css/footnote_picker.admin.css: {} |
|
||||||
css/footnote_picker.dialog.css: {} |
|
||||||
js: |
|
||||||
js/ckeditor5_plugins/footnotepicker2/build/footnotepicker2.js: {} |
|
||||||
dependencies: |
|
||||||
- core/ckeditor5 |
|
||||||
- core/drupal |
|
||||||
- core/drupal.dialog |
|
||||||
- core/jquery |
|
||||||
@ -1,366 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
/** |
|
||||||
* @file |
|
||||||
* Contains bibcite_footnotes.module. |
|
||||||
*/ |
|
||||||
|
|
||||||
use Drupal\Core\Field\EntityReferenceFieldItemListInterface; |
|
||||||
use Drupal\Core\Form\FormStateInterface; |
|
||||||
use Drupal\Core\Routing\RouteMatchInterface; |
|
||||||
use Drupal\Core\Url; |
|
||||||
use Drupal\Core\Link; |
|
||||||
use Drupal\bibcite_footnotes\CitationTools; |
|
||||||
use Drupal\bibcite_footnotes\Plugin\Filter\ReferenceFootnotesFilter; |
|
||||||
use Drupal\field\Entity\FieldConfig; |
|
||||||
|
|
||||||
/** |
|
||||||
* Implements hook_theme(). |
|
||||||
*/ |
|
||||||
function bibcite_footnotes_theme() { |
|
||||||
return [ |
|
||||||
'bibcite_footnote_link' => [ |
|
||||||
'render element' => 'fn', |
|
||||||
'template' => 'bibcite-footnote-link', |
|
||||||
], |
|
||||||
'bibcite_footnote_list' => [ |
|
||||||
'render element' => 'footnotes', |
|
||||||
'path' => \Drupal::service('extension.list.module')->getPath('bibcite_footnotes') . '/templates', |
|
||||||
'template' => 'bibcite-footnote-list', |
|
||||||
'variables' => [ |
|
||||||
'notes' => [], |
|
||||||
'note_type' => [], |
|
||||||
'config' => [], |
|
||||||
], |
|
||||||
], |
|
||||||
]; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Implements hook_help(). |
|
||||||
*/ |
|
||||||
function bibcite_footnotes_help($route_name, RouteMatchInterface $route_match) { |
|
||||||
switch ($route_name) { |
|
||||||
// Main module help for the bibcite_footnotes module. |
|
||||||
case 'help.page.bibcite_footnotes': |
|
||||||
$output = ''; |
|
||||||
$output .= '<h3>' . t('About') . '</h3>'; |
|
||||||
$output .= '<p>' . t('Inline footnote links for BibCite References') . '</p>'; |
|
||||||
return $output; |
|
||||||
|
|
||||||
default: |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Implementation of hook_preprocess_bibcite_footnote_list(). |
|
||||||
* |
|
||||||
* Gatehrs all notes and prints out Notes and References as separate lists. |
|
||||||
* |
|
||||||
* @param $variables Theme variables. |
|
||||||
* |
|
||||||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException |
|
||||||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException |
|
||||||
*/ |
|
||||||
function bibcite_footnotes_preprocess_bibcite_footnote_list(&$variables) { |
|
||||||
$config = $variables['config']; |
|
||||||
$footnotes = $variables['notes']; |
|
||||||
|
|
||||||
$notes = [ |
|
||||||
'#theme' => 'item_list', |
|
||||||
'#list_type' => 'ul', |
|
||||||
'#title' => $variables['note_type'] == $config['notes_section_label'], |
|
||||||
'#attributes' => ['class' => 'footnotes'], |
|
||||||
'#wrapper_attributes' => ['class' => 'container'], |
|
||||||
]; |
|
||||||
|
|
||||||
$notes['#attached']['library'][] = 'bibcite_footnotes/reference_footnote'; |
|
||||||
$dont_show_backlink_text = $config['reference_dont_show_backlink_text']; |
|
||||||
|
|
||||||
$citation_tools = new CitationTools(); |
|
||||||
if (empty($footnotes)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
foreach ($footnotes as $fn) { |
|
||||||
$item = [ |
|
||||||
'#id' => $fn['fn_id'], |
|
||||||
'#wrapper_attributes' => [ |
|
||||||
'class' => ['footnote'], |
|
||||||
], |
|
||||||
]; |
|
||||||
$build = []; |
|
||||||
$reference_entity_id = $fn['reference']; |
|
||||||
|
|
||||||
$footnote_link_text = ($dont_show_backlink_text) ? '^' : $fn['value']; |
|
||||||
if (!is_array($fn['ref_id'])) { |
|
||||||
$url = Url::fromUserInput('#' . $fn['ref_id'], ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-link']]); |
|
||||||
$link = Link::fromTextAndUrl(($footnote_link_text), $url)->toRenderable(); |
|
||||||
$build['footnote-link'] = $link; |
|
||||||
$override_page_in_citation = $fn['page'] ? $fn['page'] : FALSE; |
|
||||||
} |
|
||||||
else { |
|
||||||
// Output footnote that has more than one reference to it in the body. |
|
||||||
// The only difference is to insert backlinks to all references. |
|
||||||
// Helper: we need to enumerate a, b, c... |
|
||||||
$abc = str_split("abcdefghijklmnopqrstuvwxyz"); |
|
||||||
$i = 0; |
|
||||||
|
|
||||||
$url = Url::fromUserInput('#' . $fn['ref_id'][0], ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-link']]); |
|
||||||
$build['footnote-link'] = Link::fromTextAndUrl($footnote_link_text, $url)->toRenderable(); |
|
||||||
|
|
||||||
foreach ($fn['ref_id'] as $ref) { |
|
||||||
$url = Url::fromUserInput( '#' . $ref, ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-multi']]); |
|
||||||
$build[] = Link::fromTextAndUrl($abc[$i], $url)->toRenderable(); |
|
||||||
|
|
||||||
$i++; |
|
||||||
} |
|
||||||
$override_page_in_citation = FALSE; |
|
||||||
} |
|
||||||
|
|
||||||
if (isset($fn['ibid']) && $fn['ibid']) { |
|
||||||
$build['footnote-text'] = [ |
|
||||||
'#type' => 'markup', |
|
||||||
'#markup' => ' <span class="endnote-text"><span class="ibid">' |
|
||||||
. t('Ibid') . '.</span>' |
|
||||||
. (!empty($fn['page']) ? ', ' . $fn['page'] : '') |
|
||||||
. '</span>', |
|
||||||
]; |
|
||||||
} |
|
||||||
else if (!empty($fn['text'])) { |
|
||||||
$build['footnote-link'] = Link::fromTextAndUrl($footnote_link_text, $url)->toRenderable(); |
|
||||||
$build['footnote-text'] = [ |
|
||||||
'#type' => 'markup', |
|
||||||
'#markup' => ' <span class="endnote-text">' . $fn['text'] . '</span>', |
|
||||||
]; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
if (!empty($reference_entity_id)) { |
|
||||||
if (empty($fn['ibid'])) { |
|
||||||
$citation_build = $citation_tools->getRenderableReference($reference_entity_id); |
|
||||||
if ($override_page_in_citation) { |
|
||||||
$citation_build['#data']['page'] = $override_page_in_citation; |
|
||||||
} |
|
||||||
|
|
||||||
$build[] = $citation_build; |
|
||||||
} |
|
||||||
|
|
||||||
//$render = render($build); |
|
||||||
$citation_build_render = \Drupal::service('renderer')->render($citation_build); |
|
||||||
$item['sort'] = trim(strip_tags($citation_build_render)); |
|
||||||
} |
|
||||||
|
|
||||||
// $item['#markup'] = $render; |
|
||||||
$notes['#items'][] = $build; |
|
||||||
$reference_entity_id = FALSE; |
|
||||||
$render = FALSE; |
|
||||||
} |
|
||||||
|
|
||||||
$variables['notes'] = $notes; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Comparator function for sorting lists of references. |
|
||||||
* |
|
||||||
* @param $a First item to compare |
|
||||||
* @param $b Second item to compare |
|
||||||
* @return int Result of the comparison. |
|
||||||
*/ |
|
||||||
function _bibcite_footnotes_reference_array_cmp($a, $b) { |
|
||||||
$a1 = (!empty($a['sort']) ? strtolower($a['sort']) : ''); |
|
||||||
$b1 = (!empty($b['sort']) ? strtolower($b['sort']) : ''); |
|
||||||
return strcmp($a1, $b1); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Implementation of hook_preprocess_bibcite_footnote_link(). |
|
||||||
* |
|
||||||
* Construct a link inside a block of text so that it points to the reference list. |
|
||||||
* |
|
||||||
* @param $variables |
|
||||||
*/ |
|
||||||
function bibcite_footnotes_preprocess_bibcite_footnote_link(&$variables) { |
|
||||||
// $variables['fn']['fn']['#type'] = 'markeup'; |
|
||||||
// $variables['fn']['fn']['#markup'] = '<h2>Hello!</h2>'; |
|
||||||
$fn = $variables['fn']['fn']; |
|
||||||
// TODO: Make a more formal way to denote inline citations. |
|
||||||
|
|
||||||
$class = 'see-footnote'; |
|
||||||
// Generate the hover text |
|
||||||
$citation_tools = new CitationTools(); |
|
||||||
$citation_entity_id = $fn['reference']; |
|
||||||
$citation_data = $citation_tools->getRenderableReference($citation_entity_id); |
|
||||||
|
|
||||||
// Citation contains a page reference, so construct parenthetical footnote. |
|
||||||
// @TODO: Make it explicit. |
|
||||||
if (!empty($fn['page'] && !is_numeric($fn['value']))) { |
|
||||||
$fn['value'] = "({$fn['value']}, {$fn['page']})"; |
|
||||||
$citation_data['#data']['page'] = $fn['page']; |
|
||||||
$class .= '-inline'; |
|
||||||
} |
|
||||||
$citation_data_render = \Drupal::service('renderer')->render($citation_data); |
|
||||||
$title = trim(strip_tags($citation_data_render)); |
|
||||||
$url = Url::fromUserInput('#' . $fn['fn_id'], ['attributes' => ['id' => $fn['ref_id'], 'class' => $class, 'title' => $title]]); |
|
||||||
|
|
||||||
|
|
||||||
$link = Link::fromTextAndUrl($fn['value'], $url)->toRenderable(); |
|
||||||
unset($variables['fn']['fn']); |
|
||||||
$variables['fn']['fn'] = $link; |
|
||||||
// $variables['fn']['fn'][] = $link; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Implementation of hook_inline_entity_form_entity_form_alter(). |
|
||||||
* |
|
||||||
* Force all entities to be saved once they are created. |
|
||||||
* |
|
||||||
* @TODO: Add cleanup batch task for orphaned References. |
|
||||||
* |
|
||||||
* @param $form |
|
||||||
* @param \Drupal\Core\Form\FormStateInterface $form_state |
|
||||||
*/ |
|
||||||
function bibcite_footnotes_inline_entity_form_entity_form_alter(&$form, FormStateInterface &$form_state) { |
|
||||||
$form['#save_entity'] = TRUE; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Implementation of hook_form_node_form_alter(). |
|
||||||
* |
|
||||||
* This function populates the Reference list drop-down in the CKEditor drop-down. |
|
||||||
* It gathers all referenced entities of type bibcite_reference and puts them |
|
||||||
* into a JavaScript setting under drupalSettings.bibcite_footnotes.references. |
|
||||||
* |
|
||||||
* @param $form |
|
||||||
* @param \Drupal\Core\Form\FormStateInterface $form_state |
|
||||||
*/ |
|
||||||
function bibcite_footnotes_form_node_form_alter(&$form, FormStateInterface &$form_state) { |
|
||||||
$ief = $form_state->get('inline_entity_form'); |
|
||||||
if ($ief) { |
|
||||||
// Inline entity storage uses hashes to separate out the field instances. |
|
||||||
$bibcite_references = []; |
|
||||||
foreach ($ief as $ief_instance) { |
|
||||||
/** |
|
||||||
* @var FieldConfig $field_config |
|
||||||
*/ |
|
||||||
if ($field_config = $ief_instance['instance']) { |
|
||||||
|
|
||||||
// Check if this is a bibcite_reference field type. |
|
||||||
if ($field_config->getSetting('handler') == 'default:bibcite_reference') { |
|
||||||
$field_name = $field_config->get('field_name'); |
|
||||||
if (!empty($ief_instance['entities'])) { |
|
||||||
|
|
||||||
foreach ($ief_instance['entities'] as $entity_wrapper) { |
|
||||||
/** |
|
||||||
* @var \Drupal\core\Entity\EntityInterface $entity |
|
||||||
*/ |
|
||||||
$entity = $entity_wrapper['entity']; |
|
||||||
if ($entity->getEntityTypeId() == 'bibcite_reference') { |
|
||||||
list($citation_text, $citation_key) = bibcite_footnotes_get_ckeditor_select_item($entity); |
|
||||||
$bibcite_references[] = [$citation_text, $citation_key]; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
$triggering_element = $form_state->getTriggeringElement(); |
|
||||||
if (!$triggering_element) { |
|
||||||
$form['#attached']['drupalSettings']['bibcite_footnotes']['references'] = $bibcite_references; |
|
||||||
} |
|
||||||
else { |
|
||||||
$form[$triggering_element['#parents'][0]]['widget']['#attached']['library'][] = 'bibcite_footnotes/replace_citations'; |
|
||||||
$form[$triggering_element['#parents'][0]]['widget']['#attached']['drupalSettings']['bibcite_footnotes']['references'] = $bibcite_references; |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
// Not using Inline Entity Form, get the references if they exist |
|
||||||
$entity = $form_state->getFormObject()->getEntity(); |
|
||||||
$fields = $entity->getFields(); |
|
||||||
$reference_field = FALSE; |
|
||||||
foreach ($fields as $field) { |
|
||||||
$type = $field->getFieldDefinition(); |
|
||||||
if ($type->getType() == 'entity_reference') { |
|
||||||
if ($type->getSetting('handler') == 'default:bibcite_reference') { |
|
||||||
$referenced_entities = $field->referencedEntities(); |
|
||||||
$bibcite_references = []; |
|
||||||
foreach ($referenced_entities as $referenced_entity) { |
|
||||||
list($citation_text, $citation_key) = bibcite_footnotes_get_ckeditor_select_item($referenced_entity); |
|
||||||
$bibcite_references[] = [$citation_text, $citation_key]; |
|
||||||
} |
|
||||||
$form['#attached']['drupalSettings']['bibcite_footnotes']['references'] = $bibcite_references; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Construct an item to go into the CKEditor Reference drop-down list. |
|
||||||
* |
|
||||||
* @param $entity |
|
||||||
* |
|
||||||
* @return array |
|
||||||
* The form of the array is ["Citation string", [reference entity id]. |
|
||||||
*/ |
|
||||||
function bibcite_footnotes_get_ckeditor_select_item($entity): array { |
|
||||||
$serializer = \Drupal::service('serializer'); |
|
||||||
|
|
||||||
$data = $serializer->normalize($entity, 'csl'); |
|
||||||
$build = ['#theme' => 'bibcite_citation', '#data' => $data]; |
|
||||||
$build_render = \Drupal::service('renderer')->render($build); |
|
||||||
$citation_text = trim(strip_tags($build_render)); |
|
||||||
// Attempt to match up pre-saved entities with the eventual saved ones. |
|
||||||
$citation_key = $entity->id->first()->getValue()['value']; |
|
||||||
return [$citation_text, $citation_key]; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Implementation of hook_preprocess_field(). |
|
||||||
* Sort the works cited list by rendered text, which results in author(s) then title. |
|
||||||
* |
|
||||||
* @param $variables |
|
||||||
* @param $hook |
|
||||||
*/ |
|
||||||
function bibcite_footnotes_preprocess_field(&$variables, $hook) { |
|
||||||
$citation_tools = new CitationTools(); |
|
||||||
if ($variables['field_name'] == 'field_bibcite_fn_works_cited') { |
|
||||||
|
|
||||||
foreach($variables['element'] as $index => $element) { |
|
||||||
if (is_numeric($index)) { |
|
||||||
$renderable = $citation_tools->getRenderableReference($element['#bibcite_reference']); |
|
||||||
$renderable = \Drupal::service('renderer')->render($renderable); |
|
||||||
$items[] = [ |
|
||||||
'orig_index' => $index, |
|
||||||
'orig_element' => $element, |
|
||||||
'rendered' => trim(strip_tags($renderable)), |
|
||||||
]; |
|
||||||
} |
|
||||||
} |
|
||||||
uasort($items, '_bibcite_footnotes_sort_rendered_references'); |
|
||||||
$i = 0; |
|
||||||
foreach ($items as $item) { |
|
||||||
$variables['element'][$i] = $item['orig_element']; |
|
||||||
$variables['element']['#items'][$i] = $item['orig_element']; |
|
||||||
$variables['items'][$i]['content'] = $item['orig_element']; |
|
||||||
$i += 1; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Comparator function for theme field preprocess. |
|
||||||
* |
|
||||||
* @param $a |
|
||||||
* The first renderable element. |
|
||||||
* @param $b |
|
||||||
* The second renderable element. |
|
||||||
* |
|
||||||
* @return int |
|
||||||
*/ |
|
||||||
function _bibcite_footnotes_sort_rendered_references($a, $b) { |
|
||||||
if ($a['rendered'] == $b['rendered']) { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
return strtolower($a['rendered']) < strtolower($b['rendered']) ? -1 : 1; |
|
||||||
} |
|
||||||
@ -1,4 +0,0 @@ |
|||||||
Description |
|
||||||
----------- |
|
||||||
|
|
||||||
Example content type and text format to demonstrate a fully-configured Reference Footnotes setup. |
|
||||||
@ -1,13 +0,0 @@ |
|||||||
name: 'BibCite Footnotes Article with Citations' |
|
||||||
type: module |
|
||||||
description: 'Example module to show a fully-configured content type and text format with Reference Footnotes.' |
|
||||||
core_version_requirement: ^9.5 || ^10 || ^11 |
|
||||||
package: 'Bibliography & Citation' |
|
||||||
dependencies: |
|
||||||
- bibcite_footnotes:bibcite_footnotes |
|
||||||
- bibcite:bibcite_import |
|
||||||
- bibcite:bibcite_bibtex |
|
||||||
- bibcite:bibcite_endnote |
|
||||||
- bibcite:bibcite_ris |
|
||||||
- bibcite:bibcite_marc |
|
||||||
- inline_entity_form:inline_entity_form |
|
||||||
@ -1,113 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
config: |
|
||||||
- field.field.node.bibcite_fn_article_references.body |
|
||||||
- field.field.node.bibcite_fn_article_references.field_bibcite_fn_works_cited |
|
||||||
- field.field.node.bibcite_fn_article_references.field_image |
|
||||||
- field.field.node.bibcite_fn_article_references.field_tags |
|
||||||
- image.style.thumbnail |
|
||||||
- node.type.bibcite_fn_article_references |
|
||||||
module: |
|
||||||
- image |
|
||||||
- inline_entity_form |
|
||||||
- path |
|
||||||
- text |
|
||||||
id: node.bibcite_fn_article_references.default |
|
||||||
targetEntityType: node |
|
||||||
bundle: bibcite_fn_article_references |
|
||||||
mode: default |
|
||||||
content: |
|
||||||
body: |
|
||||||
type: text_textarea_with_summary |
|
||||||
weight: 7 |
|
||||||
settings: |
|
||||||
rows: 9 |
|
||||||
summary_rows: 3 |
|
||||||
placeholder: '' |
|
||||||
third_party_settings: { } |
|
||||||
region: content |
|
||||||
created: |
|
||||||
type: datetime_timestamp |
|
||||||
weight: 2 |
|
||||||
region: content |
|
||||||
settings: { } |
|
||||||
third_party_settings: { } |
|
||||||
field_bibcite_fn_works_cited: |
|
||||||
weight: 8 |
|
||||||
settings: |
|
||||||
form_mode: default |
|
||||||
label_singular: '' |
|
||||||
label_plural: '' |
|
||||||
allow_new: true |
|
||||||
allow_existing: true |
|
||||||
match_operator: CONTAINS |
|
||||||
override_labels: false |
|
||||||
collapsible: false |
|
||||||
collapsed: false |
|
||||||
allow_duplicate: false |
|
||||||
third_party_settings: { } |
|
||||||
type: inline_entity_form_complex |
|
||||||
region: content |
|
||||||
field_image: |
|
||||||
weight: 10 |
|
||||||
settings: |
|
||||||
progress_indicator: throbber |
|
||||||
preview_image_style: thumbnail |
|
||||||
third_party_settings: { } |
|
||||||
type: image_image |
|
||||||
region: content |
|
||||||
field_tags: |
|
||||||
weight: 9 |
|
||||||
settings: |
|
||||||
match_operator: CONTAINS |
|
||||||
size: 60 |
|
||||||
placeholder: '' |
|
||||||
third_party_settings: { } |
|
||||||
type: entity_reference_autocomplete |
|
||||||
region: content |
|
||||||
path: |
|
||||||
type: path |
|
||||||
weight: 5 |
|
||||||
region: content |
|
||||||
settings: { } |
|
||||||
third_party_settings: { } |
|
||||||
promote: |
|
||||||
type: boolean_checkbox |
|
||||||
settings: |
|
||||||
display_label: true |
|
||||||
weight: 3 |
|
||||||
region: content |
|
||||||
third_party_settings: { } |
|
||||||
status: |
|
||||||
type: boolean_checkbox |
|
||||||
settings: |
|
||||||
display_label: true |
|
||||||
weight: 6 |
|
||||||
region: content |
|
||||||
third_party_settings: { } |
|
||||||
sticky: |
|
||||||
type: boolean_checkbox |
|
||||||
settings: |
|
||||||
display_label: true |
|
||||||
weight: 4 |
|
||||||
region: content |
|
||||||
third_party_settings: { } |
|
||||||
title: |
|
||||||
type: string_textfield |
|
||||||
weight: 0 |
|
||||||
region: content |
|
||||||
settings: |
|
||||||
size: 60 |
|
||||||
placeholder: '' |
|
||||||
third_party_settings: { } |
|
||||||
uid: |
|
||||||
type: entity_reference_autocomplete |
|
||||||
weight: 1 |
|
||||||
settings: |
|
||||||
match_operator: CONTAINS |
|
||||||
size: 60 |
|
||||||
placeholder: '' |
|
||||||
region: content |
|
||||||
third_party_settings: { } |
|
||||||
hidden: { } |
|
||||||
@ -1,57 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
config: |
|
||||||
- field.field.node.bibcite_fn_article_references.body |
|
||||||
- field.field.node.bibcite_fn_article_references.field_bibcite_fn_works_cited |
|
||||||
- field.field.node.bibcite_fn_article_references.field_image |
|
||||||
- field.field.node.bibcite_fn_article_references.field_tags |
|
||||||
- node.type.bibcite_fn_article_references |
|
||||||
module: |
|
||||||
- image |
|
||||||
- text |
|
||||||
- user |
|
||||||
id: node.bibcite_fn_article_references.default |
|
||||||
targetEntityType: node |
|
||||||
bundle: bibcite_fn_article_references |
|
||||||
mode: default |
|
||||||
content: |
|
||||||
body: |
|
||||||
label: hidden |
|
||||||
type: text_default |
|
||||||
weight: 1 |
|
||||||
settings: { } |
|
||||||
third_party_settings: { } |
|
||||||
region: content |
|
||||||
field_bibcite_fn_works_cited: |
|
||||||
weight: 2 |
|
||||||
label: above |
|
||||||
settings: |
|
||||||
view_mode: citation |
|
||||||
link: false |
|
||||||
third_party_settings: { } |
|
||||||
type: entity_reference_entity_view |
|
||||||
region: content |
|
||||||
field_image: |
|
||||||
weight: 4 |
|
||||||
label: above |
|
||||||
settings: |
|
||||||
image_style: '' |
|
||||||
image_link: '' |
|
||||||
third_party_settings: { } |
|
||||||
type: image |
|
||||||
region: content |
|
||||||
field_tags: |
|
||||||
weight: 3 |
|
||||||
label: above |
|
||||||
settings: |
|
||||||
link: true |
|
||||||
third_party_settings: { } |
|
||||||
type: entity_reference_label |
|
||||||
region: content |
|
||||||
links: |
|
||||||
weight: 0 |
|
||||||
region: content |
|
||||||
settings: { } |
|
||||||
third_party_settings: { } |
|
||||||
hidden: { } |
|
||||||
@ -1,51 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
config: |
|
||||||
- filter.format.basic_html_with_references |
|
||||||
module: |
|
||||||
- ckeditor |
|
||||||
format: basic_html_with_references |
|
||||||
editor: ckeditor |
|
||||||
settings: |
|
||||||
toolbar: |
|
||||||
rows: |
|
||||||
- |
|
||||||
- |
|
||||||
name: Formatting |
|
||||||
items: |
|
||||||
- Bold |
|
||||||
- Italic |
|
||||||
- |
|
||||||
name: Links |
|
||||||
items: |
|
||||||
- DrupalLink |
|
||||||
- DrupalUnlink |
|
||||||
- |
|
||||||
name: Lists |
|
||||||
items: |
|
||||||
- BulletedList |
|
||||||
- NumberedList |
|
||||||
- |
|
||||||
name: Media |
|
||||||
items: |
|
||||||
- Blockquote |
|
||||||
- DrupalImage |
|
||||||
- |
|
||||||
name: Tools |
|
||||||
items: |
|
||||||
- Source |
|
||||||
- reference_footnotes |
|
||||||
plugins: |
|
||||||
stylescombo: |
|
||||||
styles: '' |
|
||||||
language: |
|
||||||
language_list: un |
|
||||||
image_upload: |
|
||||||
status: false |
|
||||||
scheme: public |
|
||||||
directory: inline-images |
|
||||||
max_size: '' |
|
||||||
max_dimensions: |
|
||||||
width: null |
|
||||||
height: null |
|
||||||
@ -1,21 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
config: |
|
||||||
- field.storage.node.body |
|
||||||
- node.type.bibcite_fn_article_references |
|
||||||
module: |
|
||||||
- text |
|
||||||
id: node.bibcite_fn_article_references.body |
|
||||||
field_name: body |
|
||||||
entity_type: node |
|
||||||
bundle: bibcite_fn_article_references |
|
||||||
label: Body |
|
||||||
description: '' |
|
||||||
required: false |
|
||||||
translatable: true |
|
||||||
default_value: { } |
|
||||||
default_value_callback: '' |
|
||||||
settings: |
|
||||||
display_summary: true |
|
||||||
field_type: text_with_summary |
|
||||||
@ -1,98 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
config: |
|
||||||
- bibcite_entity.bibcite_reference_type.artwork |
|
||||||
- bibcite_entity.bibcite_reference_type.audiovisual |
|
||||||
- bibcite_entity.bibcite_reference_type.bill |
|
||||||
- bibcite_entity.bibcite_reference_type.book |
|
||||||
- bibcite_entity.bibcite_reference_type.book_chapter |
|
||||||
- bibcite_entity.bibcite_reference_type.broadcast |
|
||||||
- bibcite_entity.bibcite_reference_type.case |
|
||||||
- bibcite_entity.bibcite_reference_type.chart |
|
||||||
- bibcite_entity.bibcite_reference_type.classical |
|
||||||
- bibcite_entity.bibcite_reference_type.conference_paper |
|
||||||
- bibcite_entity.bibcite_reference_type.conference_proceedings |
|
||||||
- bibcite_entity.bibcite_reference_type.database |
|
||||||
- bibcite_entity.bibcite_reference_type.film |
|
||||||
- bibcite_entity.bibcite_reference_type.government_report |
|
||||||
- bibcite_entity.bibcite_reference_type.hearing |
|
||||||
- bibcite_entity.bibcite_reference_type.journal |
|
||||||
- bibcite_entity.bibcite_reference_type.journal_article |
|
||||||
- bibcite_entity.bibcite_reference_type.legal_ruling |
|
||||||
- bibcite_entity.bibcite_reference_type.magazine_article |
|
||||||
- bibcite_entity.bibcite_reference_type.manuscript |
|
||||||
- bibcite_entity.bibcite_reference_type.map |
|
||||||
- bibcite_entity.bibcite_reference_type.miscellaneous |
|
||||||
- bibcite_entity.bibcite_reference_type.miscellaneous_section |
|
||||||
- bibcite_entity.bibcite_reference_type.newspaper_article |
|
||||||
- bibcite_entity.bibcite_reference_type.patent |
|
||||||
- bibcite_entity.bibcite_reference_type.personal |
|
||||||
- bibcite_entity.bibcite_reference_type.presentation |
|
||||||
- bibcite_entity.bibcite_reference_type.report |
|
||||||
- bibcite_entity.bibcite_reference_type.software |
|
||||||
- bibcite_entity.bibcite_reference_type.statute |
|
||||||
- bibcite_entity.bibcite_reference_type.thesis |
|
||||||
- bibcite_entity.bibcite_reference_type.unpublished |
|
||||||
- bibcite_entity.bibcite_reference_type.web_article |
|
||||||
- bibcite_entity.bibcite_reference_type.web_project_page |
|
||||||
- bibcite_entity.bibcite_reference_type.web_service |
|
||||||
- bibcite_entity.bibcite_reference_type.website |
|
||||||
- field.storage.node.field_bibcite_fn_works_cited |
|
||||||
- node.type.bibcite_fn_article_references |
|
||||||
id: node.bibcite_fn_article_references.field_bibcite_fn_works_cited |
|
||||||
field_name: field_bibcite_fn_works_cited |
|
||||||
entity_type: node |
|
||||||
bundle: bibcite_fn_article_references |
|
||||||
label: 'Works Cited' |
|
||||||
description: 'List of works mentioned in this article.' |
|
||||||
required: false |
|
||||||
translatable: true |
|
||||||
default_value: { } |
|
||||||
default_value_callback: '' |
|
||||||
settings: |
|
||||||
handler: 'default:bibcite_reference' |
|
||||||
handler_settings: |
|
||||||
target_bundles: |
|
||||||
artwork: artwork |
|
||||||
audiovisual: audiovisual |
|
||||||
bill: bill |
|
||||||
book: book |
|
||||||
book_chapter: book_chapter |
|
||||||
broadcast: broadcast |
|
||||||
case: case |
|
||||||
chart: chart |
|
||||||
classical: classical |
|
||||||
conference_paper: conference_paper |
|
||||||
conference_proceedings: conference_proceedings |
|
||||||
database: database |
|
||||||
film: film |
|
||||||
government_report: government_report |
|
||||||
hearing: hearing |
|
||||||
journal: journal |
|
||||||
journal_article: journal_article |
|
||||||
legal_ruling: legal_ruling |
|
||||||
magazine_article: magazine_article |
|
||||||
manuscript: manuscript |
|
||||||
map: map |
|
||||||
miscellaneous: miscellaneous |
|
||||||
miscellaneous_section: miscellaneous_section |
|
||||||
newspaper_article: newspaper_article |
|
||||||
patent: patent |
|
||||||
personal: personal |
|
||||||
presentation: presentation |
|
||||||
report: report |
|
||||||
software: software |
|
||||||
statute: statute |
|
||||||
thesis: thesis |
|
||||||
unpublished: unpublished |
|
||||||
web_article: web_article |
|
||||||
web_project_page: web_project_page |
|
||||||
web_service: web_service |
|
||||||
website: website |
|
||||||
sort: |
|
||||||
field: title |
|
||||||
direction: ASC |
|
||||||
auto_create: false |
|
||||||
auto_create_bundle: artwork |
|
||||||
field_type: entity_reference |
|
||||||
@ -1,37 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
config: |
|
||||||
- field.storage.node.field_image |
|
||||||
- node.type.bibcite_fn_article_references |
|
||||||
module: |
|
||||||
- image |
|
||||||
id: node.bibcite_fn_article_references.field_image |
|
||||||
field_name: field_image |
|
||||||
entity_type: node |
|
||||||
bundle: bibcite_fn_article_references |
|
||||||
label: Image |
|
||||||
description: '' |
|
||||||
required: false |
|
||||||
translatable: true |
|
||||||
default_value: { } |
|
||||||
default_value_callback: '' |
|
||||||
settings: |
|
||||||
file_directory: '[date:custom:Y]-[date:custom:m]' |
|
||||||
file_extensions: 'png gif jpg jpeg' |
|
||||||
max_filesize: '' |
|
||||||
max_resolution: '' |
|
||||||
min_resolution: '' |
|
||||||
alt_field: true |
|
||||||
alt_field_required: true |
|
||||||
title_field: false |
|
||||||
title_field_required: false |
|
||||||
default_image: |
|
||||||
uuid: '' |
|
||||||
alt: '' |
|
||||||
title: '' |
|
||||||
width: null |
|
||||||
height: null |
|
||||||
handler: 'default:file' |
|
||||||
handler_settings: { } |
|
||||||
field_type: image |
|
||||||
@ -1,28 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
config: |
|
||||||
- field.storage.node.field_tags |
|
||||||
- node.type.bibcite_fn_article_references |
|
||||||
- taxonomy.vocabulary.tags |
|
||||||
id: node.bibcite_fn_article_references.field_tags |
|
||||||
field_name: field_tags |
|
||||||
entity_type: node |
|
||||||
bundle: bibcite_fn_article_references |
|
||||||
label: Tags |
|
||||||
description: 'Enter a comma-separated list. For example: Amsterdam, Mexico City, "Cleveland, Ohio"' |
|
||||||
required: false |
|
||||||
translatable: true |
|
||||||
default_value: { } |
|
||||||
default_value_callback: '' |
|
||||||
settings: |
|
||||||
handler: 'default:taxonomy_term' |
|
||||||
handler_settings: |
|
||||||
target_bundles: |
|
||||||
tags: tags |
|
||||||
sort: |
|
||||||
field: name |
|
||||||
direction: asc |
|
||||||
auto_create: true |
|
||||||
auto_create_bundle: '' |
|
||||||
field_type: entity_reference |
|
||||||
@ -1,87 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
module: |
|
||||||
- bibcite_footnotes |
|
||||||
- editor |
|
||||||
- footnotes |
|
||||||
name: 'Basic HTML with References' |
|
||||||
format: basic_html_with_references |
|
||||||
weight: 0 |
|
||||||
filters: |
|
||||||
filter_reference_footnotes: |
|
||||||
id: filter_reference_footnotes |
|
||||||
provider: bibcite_footnotes |
|
||||||
status: true |
|
||||||
weight: -50 |
|
||||||
settings: |
|
||||||
footnotes_collapse: '1' |
|
||||||
footnotes_ibid: '0' |
|
||||||
notes_section_label: Notes |
|
||||||
reference_dont_show_backlink_text: '0' |
|
||||||
works_cited_sort_by: alphabetical |
|
||||||
editor_file_reference: |
|
||||||
id: editor_file_reference |
|
||||||
provider: editor |
|
||||||
status: true |
|
||||||
weight: -45 |
|
||||||
settings: { } |
|
||||||
filter_html_image_secure: |
|
||||||
id: filter_html_image_secure |
|
||||||
provider: filter |
|
||||||
status: true |
|
||||||
weight: -46 |
|
||||||
settings: { } |
|
||||||
filter_url: |
|
||||||
id: filter_url |
|
||||||
provider: filter |
|
||||||
status: false |
|
||||||
weight: -41 |
|
||||||
settings: |
|
||||||
filter_url_length: 72 |
|
||||||
filter_html: |
|
||||||
id: filter_html |
|
||||||
provider: filter |
|
||||||
status: true |
|
||||||
weight: -49 |
|
||||||
settings: |
|
||||||
allowed_html: '<a href hreflang id class="" title> <div id class=""> <em> <strong> <cite> <blockquote cite> <code> <ul type class=""> <ol id type class=""> <li id class=""> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id> <span id class=""> <sup> <img src alt data-entity-type data-entity-uuid data-align data-caption> <p> <fn id>' |
|
||||||
filter_html_help: true |
|
||||||
filter_html_nofollow: false |
|
||||||
filter_autop: |
|
||||||
id: filter_autop |
|
||||||
provider: filter |
|
||||||
status: false |
|
||||||
weight: -42 |
|
||||||
settings: { } |
|
||||||
filter_align: |
|
||||||
id: filter_align |
|
||||||
provider: filter |
|
||||||
status: true |
|
||||||
weight: -48 |
|
||||||
settings: { } |
|
||||||
filter_caption: |
|
||||||
id: filter_caption |
|
||||||
provider: filter |
|
||||||
status: true |
|
||||||
weight: -47 |
|
||||||
settings: { } |
|
||||||
filter_htmlcorrector: |
|
||||||
id: filter_htmlcorrector |
|
||||||
provider: filter |
|
||||||
status: false |
|
||||||
weight: -40 |
|
||||||
settings: { } |
|
||||||
filter_html_escape: |
|
||||||
id: filter_html_escape |
|
||||||
provider: filter |
|
||||||
status: false |
|
||||||
weight: -43 |
|
||||||
settings: { } |
|
||||||
filter_footnotes: |
|
||||||
id: filter_footnotes |
|
||||||
provider: footnotes |
|
||||||
status: false |
|
||||||
weight: -44 |
|
||||||
settings: |
|
||||||
footnotes_collapse: '0' |
|
||||||
@ -1,17 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
module: |
|
||||||
- menu_ui |
|
||||||
third_party_settings: |
|
||||||
menu_ui: |
|
||||||
available_menus: |
|
||||||
- main |
|
||||||
parent: 'main:' |
|
||||||
name: 'Article with References' |
|
||||||
type: bibcite_fn_article_references |
|
||||||
description: 'Article that includes a Works Cited field and in-text references.' |
|
||||||
help: '' |
|
||||||
new_revision: true |
|
||||||
preview_mode: 1 |
|
||||||
display_submitted: true |
|
||||||
@ -1,38 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "drupal/footnotes", |
|
||||||
"description": "Add automatically numbered footnotes to your posts.", |
|
||||||
"type": "drupal-module", |
|
||||||
"homepage": "https://drupal.org/project/footnotes", |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Andrii Aleksandrov (id.aleks)", |
|
||||||
"homepage": "https://www.drupal.org/u/idaleks", |
|
||||||
"role": "Maintainer" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "Oleksandr Dekhteruk (pifagor)", |
|
||||||
"homepage": "https://www.drupal.org/u/pifagor", |
|
||||||
"role": "Maintainer" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "Fernando Conceição (yukare)", |
|
||||||
"homepage": "https://www.drupal.org/u/yukare", |
|
||||||
"role": "Maintainer" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "Henrik Ingo (hingo)", |
|
||||||
"homepage": "https://www.drupal.org/u/hingo", |
|
||||||
"role": "Maintainer" |
|
||||||
} |
|
||||||
], |
|
||||||
"support": { |
|
||||||
"issues": "https://drupal.org/project/issues/footnotes", |
|
||||||
"source": "https://cgit.drupalcode.org/footnotes" |
|
||||||
}, |
|
||||||
"license": "GPL-2.0+", |
|
||||||
"minimum-stability": "dev", |
|
||||||
"require": { |
|
||||||
"drupal/core": ">=8.6", |
|
||||||
"drupal/fakeobjects": "^1.0" |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,24 +0,0 @@ |
|||||||
langcode: en |
|
||||||
status: true |
|
||||||
dependencies: |
|
||||||
module: |
|
||||||
- bibcite_entity |
|
||||||
- node |
|
||||||
third_party_settings: |
|
||||||
field_permissions: |
|
||||||
permission_type: public |
|
||||||
_core: |
|
||||||
default_config_hash: pxSiuPskUjLuu_0TFIFVYFyZtkIelIPBysbXt_LyLVk |
|
||||||
id: node.field_bibcite_fn_works_cited |
|
||||||
field_name: field_bibcite_fn_works_cited |
|
||||||
entity_type: node |
|
||||||
type: entity_reference |
|
||||||
settings: |
|
||||||
target_type: bibcite_reference |
|
||||||
module: core |
|
||||||
locked: false |
|
||||||
cardinality: -1 |
|
||||||
translatable: true |
|
||||||
indexes: { } |
|
||||||
persist_with_no_fields: false |
|
||||||
custom_storage: false |
|
||||||
@ -1,19 +0,0 @@ |
|||||||
filter_settings.filter_reference_footnotes: |
|
||||||
type: mapping |
|
||||||
label: 'Reference Footnotes filter settings' |
|
||||||
mapping: |
|
||||||
footnotes_collapse: |
|
||||||
type: boolean |
|
||||||
label: 'Collapse identical footnotes' |
|
||||||
footnotes_ibid: |
|
||||||
type: boolean |
|
||||||
label: 'Use Ibid.' |
|
||||||
notes_section_label: |
|
||||||
type: label |
|
||||||
label: 'Notes section heading label' |
|
||||||
reference_dont_show_backlink_text: |
|
||||||
type: boolean |
|
||||||
label: "Don't show note value text in reference list" |
|
||||||
works_cited_sort_by: |
|
||||||
type: string |
|
||||||
label: 'Sort works cited by' |
|
||||||
@ -1,95 +0,0 @@ |
|||||||
|
|
||||||
.footnote-list .footnotes .footnote-link, |
|
||||||
.footnote-list .footnotes .footnote-multi { |
|
||||||
float: left; |
|
||||||
} |
|
||||||
.footnote-list .footnotes .footnote-link::after, |
|
||||||
.footnote-list .footnotes .footnote-multi::after { |
|
||||||
content: " "; |
|
||||||
white-space: pre; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* CSS specific to Bibcite Footnotes module. |
|
||||||
* (Borrowed from Footnotes module. |
|
||||||
* |
|
||||||
* |
|
||||||
* Thanks to binford2k@lug.wsu.edu for this tip and drinkypoo |
|
||||||
* for the question leading up to it. http://drupal.org/node/80538 |
|
||||||
*/ |
|
||||||
|
|
||||||
/* Add empty space before footnotes and a black line on top. */ |
|
||||||
.footnotes { |
|
||||||
clear: both; |
|
||||||
margin-top: 4em; |
|
||||||
margin-bottom: 2em; |
|
||||||
border-top: 1px solid #000; |
|
||||||
} |
|
||||||
/* Make footnotes appear in a smaller font */ |
|
||||||
.footnotes { |
|
||||||
font-size: 0.9em; |
|
||||||
} |
|
||||||
/* |
|
||||||
Make the footnote a supertext^1 |
|
||||||
*/ |
|
||||||
.see-footnote { |
|
||||||
vertical-align: top; |
|
||||||
position: relative; |
|
||||||
top: -0.25em; |
|
||||||
font-size: 0.9em; |
|
||||||
} |
|
||||||
/* Hide the bullet of the UL list of footnotes */ |
|
||||||
|
|
||||||
ul.footnotes { |
|
||||||
list-style-type: none; |
|
||||||
margin-left: 0; |
|
||||||
padding-left: 0; |
|
||||||
} |
|
||||||
ul.footnotes li { |
|
||||||
margin-left: 2.5em; |
|
||||||
list-style-type: none; |
|
||||||
background: none; /* Garland theme sets a bullet via background image, this must be unset! See bug 861634 */ |
|
||||||
} |
|
||||||
/* Move the footnote number outside of the margin for footnote text (hanging indent) */ |
|
||||||
ul.footnotes { |
|
||||||
/* This is apparently very needed for the "position: absolute;" below to work correctly */ |
|
||||||
position: relative; |
|
||||||
} |
|
||||||
.footnotes .footnote-label { |
|
||||||
position: absolute; |
|
||||||
left: 0; |
|
||||||
z-index: 2; |
|
||||||
} |
|
||||||
/* Highlight the target footnote (or ref number, if a backlink was used) when user clicks a footnote. */ |
|
||||||
.see-footnote:target, |
|
||||||
.footnotes .footnote:target { |
|
||||||
background-color: #eee; |
|
||||||
} |
|
||||||
.see-footnote:target { |
|
||||||
border: solid 1px #aaa; |
|
||||||
} |
|
||||||
/* Note: This CSS has a minor bug on all versions of IE in that the footnote numbers |
|
||||||
are aligned with the absolute bottom of their space, thus being a couple of pixels |
|
||||||
lower than their corresponding line of text. IE5.5 has a serious bug in that the numbers |
|
||||||
are not shifted left at all, thus being garbled together with the start of their text. */ |
|
||||||
|
|
||||||
/* |
|
||||||
Make the multiple backlinks a supertext^1 |
|
||||||
*/ |
|
||||||
.footnotes .footnote-multi { |
|
||||||
vertical-align: top; |
|
||||||
position: relative; |
|
||||||
top: -0.25em; |
|
||||||
font-size: 0.75em; |
|
||||||
} |
|
||||||
/* |
|
||||||
* Textile Footnotes |
|
||||||
*/ |
|
||||||
/* First footnote */ |
|
||||||
#fn1 { |
|
||||||
border-top: 1px solid #000; |
|
||||||
margin-top: 3em; |
|
||||||
} |
|
||||||
.footnote { |
|
||||||
font-size: 0.9em; |
|
||||||
} |
|
||||||
@ -1,10 +0,0 @@ |
|||||||
name: Footnotes |
|
||||||
description: 'Add automatically numbered footnotes to your posts.' |
|
||||||
|
|
||||||
type: module |
|
||||||
core_version_requirement: ^8 || ^9 |
|
||||||
|
|
||||||
dependencies: |
|
||||||
- 'fakeobjects:fakeobjects' |
|
||||||
test_dependencies: |
|
||||||
- 'fakeobjects:fakeobjects' |
|
||||||
@ -1,45 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
/** |
|
||||||
* @file |
|
||||||
* Install, update and uninstall functions for the Footnotes module. |
|
||||||
*/ |
|
||||||
|
|
||||||
/** |
|
||||||
* Implements hook_requirements(). |
|
||||||
*/ |
|
||||||
function footnotes_requirements($phase) { |
|
||||||
if ($phase != 'runtime') { |
|
||||||
return []; |
|
||||||
} |
|
||||||
|
|
||||||
// Check if fakeobjects module is enabled and properly configured. |
|
||||||
$fakeobjects_exist = \Drupal::moduleHandler()->moduleExists('fakeobjects'); |
|
||||||
if ($fakeobjects_exist) { |
|
||||||
$fakeobjects_requirements = fakeobjects_requirements($phase); |
|
||||||
if ($fakeobjects_requirements['fakeobjects']['severity'] === REQUIREMENT_OK) { |
|
||||||
$requirements['footnotes'] = [ |
|
||||||
'title' => t('Footnotes'), |
|
||||||
'value' => t('Footnotes requirements are OK.'), |
|
||||||
'severity' => REQUIREMENT_OK, |
|
||||||
]; |
|
||||||
} |
|
||||||
else { |
|
||||||
$requirements['footnotes'] = [ |
|
||||||
'title' => t('Footnotes'), |
|
||||||
'value' => t('Footnotes requirements are not properly configured. Please check Fakeobjects module requirements.'), |
|
||||||
'severity' => REQUIREMENT_ERROR, |
|
||||||
]; |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
$requirements['footnotes'] = [ |
|
||||||
'title' => t('Footnotes'), |
|
||||||
'value' => t("<a href=':href'>Fakeobjects module</a> isn't installed/enabled.", [':href' => 'https://www.drupal.org/project/fakeobjects']), |
|
||||||
'severity' => REQUIREMENT_ERROR, |
|
||||||
'description' => t('Footnotes module has a dependency on Fakeobjects module. Ensure that Fakeobjects module is enabled and configured.'), |
|
||||||
]; |
|
||||||
} |
|
||||||
|
|
||||||
return $requirements; |
|
||||||
} |
|
||||||
@ -1,5 +0,0 @@ |
|||||||
footnotes: |
|
||||||
version: VERSION |
|
||||||
css: |
|
||||||
component: |
|
||||||
assets/css/footnotes.css: {} |
|
||||||
@ -1,92 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
/** |
|
||||||
* @file |
|
||||||
* This file contains the hooks for Footnotes module. |
|
||||||
* |
|
||||||
* The Footnotes module is a filter that can be used to insert |
|
||||||
* automatically numbered footnotes into Drupal texts. |
|
||||||
*/ |
|
||||||
|
|
||||||
use Drupal\Core\Routing\RouteMatchInterface; |
|
||||||
use Drupal\Core\Url; |
|
||||||
|
|
||||||
/** |
|
||||||
* Implements hook_help(). |
|
||||||
*/ |
|
||||||
function footnotes_help($route_name, RouteMatchInterface $route_match) { |
|
||||||
switch ($route_name) { |
|
||||||
case 'help.page.footnotes': |
|
||||||
return t("Insert automatically numbered footnotes using <fn> or [fn] tags. Enable the footnotes text filter <a href=':href'>here</a>", [ |
|
||||||
':href' => Url::fromRoute('filter.admin_overview')->toString(), |
|
||||||
]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Implements hook_theme(). |
|
||||||
* |
|
||||||
* Thanks to emfabric for this implementation. http://drupal.org/node/221156 |
|
||||||
*/ |
|
||||||
function footnotes_theme() { |
|
||||||
return [ |
|
||||||
'footnote_link' => [ |
|
||||||
'variables' => [ |
|
||||||
'fn' => NULL, |
|
||||||
], |
|
||||||
], |
|
||||||
'footnote_list' => [ |
|
||||||
'variables' => [ |
|
||||||
'footnotes'=> NULL, |
|
||||||
], |
|
||||||
], |
|
||||||
]; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Helper for other filters, check if Footnotes is present in your filter chain. |
|
||||||
* |
|
||||||
* Note: Due to changes in Filter API, the arguments to this function have |
|
||||||
* changed in Drupal 7. |
|
||||||
* |
|
||||||
* Other filters may leverage the Footnotes functionality in a simple way: |
|
||||||
* by outputting markup with <fn>...</fn> tags within. |
|
||||||
* |
|
||||||
* This creates a dependency, the Footnotes filter must be present later in |
|
||||||
* "Input format". By calling this helper function the other filters that |
|
||||||
* depend on Footnotes may check whether Footnotes is present later in the chain |
|
||||||
* of filters in the current Input format. |
|
||||||
* |
|
||||||
* If this function returns true, the caller may depend on Footnotes. Function |
|
||||||
* returns false if caller may not depend on Footnotes. |
|
||||||
* |
|
||||||
* You should also put "dependencies = footnotes" in your module.info file. |
|
||||||
* |
|
||||||
* Example usage: |
|
||||||
* <code> |
|
||||||
* _filter_example_process( $text, $filter, $format ) { |
|
||||||
* ... |
|
||||||
* if(footnotes_is_footnotes_later($format, $filter)) { |
|
||||||
* //output markup which may include [fn] tags |
|
||||||
* } |
|
||||||
* else { |
|
||||||
* // must make do without footnotes features |
|
||||||
* // can also emit warning/error that user should install and configure |
|
||||||
* // footnotes module |
|
||||||
* } |
|
||||||
* ... |
|
||||||
* } |
|
||||||
* </code> |
|
||||||
* |
|
||||||
* @param object $format |
|
||||||
* The text format object caller is part of. |
|
||||||
* @param object $caller_filter |
|
||||||
* The filter object representing the caller (in this text format). |
|
||||||
* |
|
||||||
* @return True |
|
||||||
* If Footnotes is present after $caller in $format. |
|
||||||
*/ |
|
||||||
function footnotes_is_footnotes_later($format, $caller_filter) { |
|
||||||
return $format['filter_footnotes']['weight'] > $caller_filter['weight']; |
|
||||||
} |
|
||||||
@ -1,116 +0,0 @@ |
|||||||
(function() { |
|
||||||
function referenceFootnotesDialog( editor, isEdit ) { |
|
||||||
return { |
|
||||||
title : Drupal.t('Reference Footnotes Dialog'), |
|
||||||
minWidth : 500, |
|
||||||
minHeight : 50, |
|
||||||
contents : [ |
|
||||||
{ |
|
||||||
id: 'info', |
|
||||||
label: Drupal.t('Add a reference footnote'), |
|
||||||
title: Drupal.t('Add a reference footnote'), |
|
||||||
elements: |
|
||||||
[ |
|
||||||
{ |
|
||||||
id: 'reference', |
|
||||||
type: 'select', |
|
||||||
items: [[" - None - ", 0]].concat(typeof(drupalSettings.bibcite_footnotes) !== 'undefined' ? drupalSettings.bibcite_footnotes.references : []), |
|
||||||
label: Drupal.t('Reference Footnote item:'), |
|
||||||
setup: function (element) { |
|
||||||
if (isEdit) |
|
||||||
this.setValue(element.getAttribute('reference')); |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 'footnote', |
|
||||||
type: 'textarea', |
|
||||||
label: Drupal.t('Or add free-form footnote text :'), |
|
||||||
setup: function (element) { |
|
||||||
if (isEdit) { |
|
||||||
var markup = element.getHtml(); |
|
||||||
|
|
||||||
this.setValue(markup); |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 'html-help', |
|
||||||
type: 'html', |
|
||||||
html: 'HTML tags can be used, e.g., <strong>, <em>, <a href="...">', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 'page', |
|
||||||
type: 'text', |
|
||||||
labelLayout: 'horizontal', |
|
||||||
label: Drupal.t('Page(s):'), |
|
||||||
style: 'float:left:width:50px', |
|
||||||
setup: function (element) { |
|
||||||
if (isEdit) { |
|
||||||
this.setValue(element.getAttribute('page')); |
|
||||||
} |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 'value', |
|
||||||
type: 'text', |
|
||||||
label: Drupal.t('Value :'), |
|
||||||
labelLayout: 'horizontal', |
|
||||||
style: 'float:left;width:200px;', |
|
||||||
setup: function (element) { |
|
||||||
if (isEdit) |
|
||||||
this.setValue(element.getAttribute('value')); |
|
||||||
} |
|
||||||
|
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 'value-help', |
|
||||||
type: 'html', |
|
||||||
html: 'Leave blank for an automatic sequential reference number, or enter a custom footnote value', |
|
||||||
} |
|
||||||
], |
|
||||||
} |
|
||||||
], |
|
||||||
onShow : function() { |
|
||||||
if (isEdit) { |
|
||||||
this.fakeObj = CKEDITOR.plugins.reference_footnotes.getSelectedFootnote(editor); |
|
||||||
this.realObj = editor.restoreRealElement(this.fakeObj); |
|
||||||
} |
|
||||||
var select = this.parts.contents.$.getElementsByTagName('select'); |
|
||||||
var selectBox = select.item(0); |
|
||||||
// Remove all but the default 'None' item from teh list.
|
|
||||||
var i; |
|
||||||
for (i = selectBox.options.length - 1; i >= 1; i--) { |
|
||||||
selectBox.remove(i) |
|
||||||
} |
|
||||||
|
|
||||||
// Re-add buttons from the current state of Settings.
|
|
||||||
if (typeof (drupalSettings.bibcite_footnotes) !== 'undefined') { |
|
||||||
|
|
||||||
drupalSettings.bibcite_footnotes.references.forEach(function (reference) { |
|
||||||
var newReference = document.createElement('option'); |
|
||||||
newReference.text = reference[0]; |
|
||||||
newReference.setAttribute("value", reference[1]); |
|
||||||
selectBox.add(newReference); |
|
||||||
}); |
|
||||||
} |
|
||||||
this.setupContent( this.realObj ); |
|
||||||
}, |
|
||||||
onOk : function() { |
|
||||||
var referenceNote = this.getValueOf('info', 'reference'); |
|
||||||
var textNote = this.getValueOf('info', 'footnote'); |
|
||||||
var page = this.getValueOf('info', 'page'); |
|
||||||
CKEDITOR.plugins.reference_footnotes.createFootnote( editor, this.realObj, textNote, this.getValueOf('info', 'value'), referenceNote, page); |
|
||||||
delete this.fakeObj; |
|
||||||
delete this.realObj; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
CKEDITOR.dialog.add( 'createreferencefootnotes', function( editor ) { |
|
||||||
return referenceFootnotesDialog( editor ); |
|
||||||
}); |
|
||||||
CKEDITOR.dialog.add( 'editreferencefootnotes', function( editor ) { |
|
||||||
return referenceFootnotesDialog( editor, 1 ); |
|
||||||
}); |
|
||||||
})(); |
|
||||||
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 906 B |
|
Before Width: | Height: | Size: 265 B |
|
Before Width: | Height: | Size: 443 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 263 B |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 225 B |
|
Before Width: | Height: | Size: 813 B |
@ -1,143 +0,0 @@ |
|||||||
(function() { |
|
||||||
CKEDITOR.plugins.add( 'reference_footnotes', |
|
||||||
{ |
|
||||||
requires : [ 'fakeobjects','dialog' ], |
|
||||||
icons: 'reference_footnotes', |
|
||||||
onLoad: function() { |
|
||||||
var icon_path = window.location.origin + this.path + 'images/fn_icon2.png'; |
|
||||||
var ref_icon_path = window.location.origin + this.path + 'images/fn_icon3.png'; |
|
||||||
CKEDITOR.addCss( |
|
||||||
'.cke_reference_footnote' + |
|
||||||
'{' + |
|
||||||
'background-image: url(' + CKEDITOR.getUrl( ref_icon_path ) + ');' + |
|
||||||
'background-position: center center;' + |
|
||||||
'background-repeat: no-repeat;' + |
|
||||||
'width: 16px;' + |
|
||||||
'height: 16px;' + |
|
||||||
'}' + |
|
||||||
'.cke_footnote' + |
|
||||||
'{' + |
|
||||||
'background-image: url(' + CKEDITOR.getUrl( icon_path ) + ');' + |
|
||||||
'background-position: center center;' + |
|
||||||
'background-repeat: no-repeat;' + |
|
||||||
'width: 16px;' + |
|
||||||
'height: 16px;' + |
|
||||||
'}' |
|
||||||
|
|
||||||
); |
|
||||||
}, |
|
||||||
beforeInit: function( editor ) |
|
||||||
{ |
|
||||||
// Adapt some critical editor configuration for better support
|
|
||||||
// of BBCode environment.
|
|
||||||
var config = editor.config; |
|
||||||
CKEDITOR.tools.extend( config, |
|
||||||
{ |
|
||||||
enterMode : CKEDITOR.ENTER_BR, |
|
||||||
basicEntities: false, |
|
||||||
entities : false, |
|
||||||
fillEmptyBlocks : false |
|
||||||
}, true ); |
|
||||||
}, |
|
||||||
init: function( editor ) |
|
||||||
{ |
|
||||||
|
|
||||||
editor.addCommand('createreferencefootnotes', new CKEDITOR.dialogCommand('createreferencefootnotes', { |
|
||||||
allowedContent: 'fn[value]' |
|
||||||
})); |
|
||||||
editor.addCommand('editreferencefootnotes', new CKEDITOR.dialogCommand('editreferencefootnotes', { |
|
||||||
allowedContent: 'fn[value]' |
|
||||||
})); |
|
||||||
|
|
||||||
// Drupal Wysiwyg requirement: The first argument to editor.ui.addButton()
|
|
||||||
// must be equal to the key used in $plugins[<pluginName>]['buttons'][<key>]
|
|
||||||
// in hook_wysiwyg_plugin().
|
|
||||||
editor.ui.addButton && editor.ui.addButton( 'reference_footnotes', { |
|
||||||
label: Drupal.t('Add a reference footnote'), |
|
||||||
command: 'createreferencefootnotes', |
|
||||||
icon: 'reference_footnotes' |
|
||||||
}); |
|
||||||
|
|
||||||
if (editor.addMenuItems) { |
|
||||||
editor.addMenuGroup('reference_footnotes', 100); |
|
||||||
editor.addMenuItems({ |
|
||||||
footnotes: { |
|
||||||
label: Drupal.t('Edit footnote'), |
|
||||||
command: 'editreferencefootnotes', |
|
||||||
icon: 'reference_footnotes', |
|
||||||
group: 'reference_footnotes' |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
if (editor.contextMenu) { |
|
||||||
editor.contextMenu.addListener( function( element, selection ) { |
|
||||||
if ( !element || element.data('cke-real-element-type') != 'fn' ) |
|
||||||
return null; |
|
||||||
|
|
||||||
return { footnotes: CKEDITOR.TRISTATE_ON }; |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
editor.on( 'doubleclick', function( evt ) { |
|
||||||
if ( CKEDITOR.plugins.reference_footnotes.getSelectedFootnote( editor ) ) |
|
||||||
{ |
|
||||||
evt.data.dialog = 'editreferencefootnotes'; |
|
||||||
} |
|
||||||
}, null, null, 1); // Ensure this event fires after the 'footnotes' event so we can decide which dialog to show.
|
|
||||||
|
|
||||||
CKEDITOR.dialog.add( 'createreferencefootnotes', this.path + 'dialogs/footnotes.js' ); |
|
||||||
CKEDITOR.dialog.add( 'editreferencefootnotes', this.path + 'dialogs/footnotes.js' ); |
|
||||||
}, |
|
||||||
afterInit : function( editor ) { |
|
||||||
var dataProcessor = editor.dataProcessor, |
|
||||||
dataFilter = dataProcessor && dataProcessor.dataFilter; |
|
||||||
|
|
||||||
if (dataFilter) { |
|
||||||
dataFilter.addRules({ |
|
||||||
elements: { |
|
||||||
fn: function(element ) { |
|
||||||
|
|
||||||
return editor.createFakeParserElement(element, 'cke_reference_footnote', 'hiddenfield', false); |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
})(); |
|
||||||
|
|
||||||
CKEDITOR.plugins.reference_footnotes = { |
|
||||||
createFootnote: function( editor, origElement, text, value, reference, page) { |
|
||||||
if (!origElement) { |
|
||||||
var realElement = CKEDITOR.dom.element.createFromHtml('<fn></fn>'); |
|
||||||
} |
|
||||||
else { |
|
||||||
realElement = origElement; |
|
||||||
} |
|
||||||
|
|
||||||
if (text && text.length > 0 ) { |
|
||||||
realElement.setHtml(text); |
|
||||||
} |
|
||||||
realElement.setAttribute('value',value); |
|
||||||
if (page && page.length > 0) { |
|
||||||
realElement.setAttribute('page', page); |
|
||||||
} |
|
||||||
if (reference && reference.length > 0) { |
|
||||||
realElement.setAttribute('reference', reference); |
|
||||||
} |
|
||||||
|
|
||||||
var fakeElement = editor.createFakeElement( realElement , 'cke_reference_footnote', 'hiddenfield', false ); |
|
||||||
editor.insertElement(fakeElement); |
|
||||||
}, |
|
||||||
|
|
||||||
getSelectedFootnote: function( editor ) { |
|
||||||
var selection = editor.getSelection(); |
|
||||||
var element = selection.getSelectedElement(); |
|
||||||
var seltype = selection.getType(); |
|
||||||
|
|
||||||
if ( seltype == CKEDITOR.SELECTION_ELEMENT && element.data('cke-real-element-type') == 'hiddenfield') { |
|
||||||
return element; |
|
||||||
} |
|
||||||
} |
|
||||||
}; |
|
||||||
@ -1,28 +0,0 @@ |
|||||||
/** |
|
||||||
* @file |
|
||||||
* Provides JavaScript additions to entity embed dialog. |
|
||||||
* |
|
||||||
* This file provides popup windows for previewing embedded entities from the |
|
||||||
* embed dialog. |
|
||||||
*/ |
|
||||||
|
|
||||||
(function ($, Drupal) { |
|
||||||
|
|
||||||
"use strict"; |
|
||||||
|
|
||||||
Drupal.behaviors.bibciteFootnotesReplaceCitations = { |
|
||||||
attach: function attach(context, settings) { |
|
||||||
/* |
|
||||||
if (CKEDITOR.instances) { |
|
||||||
for (var instance in CKEDITOR.instances) { |
|
||||||
var editor = CKEDITOR.instances[instance]; |
|
||||||
var config = editor.config; |
|
||||||
var name = editor.name; |
|
||||||
editor.destroy(); |
|
||||||
CKEDITOR.replace(name, config); |
|
||||||
} |
|
||||||
} |
|
||||||
*/ |
|
||||||
} |
|
||||||
} |
|
||||||
})(jQuery, Drupal); |
|
||||||
@ -1,24 +0,0 @@ |
|||||||
<?php |
|
||||||
/** |
|
||||||
* Created by PhpStorm. |
|
||||||
* User: aoneill |
|
||||||
* Date: 2018-10-30 |
|
||||||
* Time: 2:36 PM |
|
||||||
*/ |
|
||||||
|
|
||||||
namespace Drupal\bibcite_footnotes; |
|
||||||
|
|
||||||
|
|
||||||
class CitationTools { |
|
||||||
|
|
||||||
public function getRenderableReference($reference_entity) { |
|
||||||
if (is_numeric($reference_entity)) { |
|
||||||
$reference_entity = \Drupal::entityTypeManager() |
|
||||||
->getStorage('bibcite_reference') |
|
||||||
->load($reference_entity); |
|
||||||
} |
|
||||||
$serializer = \Drupal::service('serializer'); |
|
||||||
$data = $serializer->normalize($reference_entity, 'csl'); |
|
||||||
return ['#theme' => 'bibcite_citation', '#data' => $data]; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,76 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
namespace Drupal\bibcite_footnotes\Plugin\BibCiteProcessor; |
|
||||||
|
|
||||||
//use AcademicPuma\CiteProc\CiteProc; |
|
||||||
use Seboettg\CiteProc\CiteProc; |
|
||||||
use Drupal\Core\Config\ConfigFactoryInterface; |
|
||||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; |
|
||||||
use Drupal\bibcite\Plugin\BibCiteProcessorBase; |
|
||||||
use Drupal\bibcite\Plugin\BibCiteProcessorInterface; |
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* Defines a style provider based on citeproc-php library. |
|
||||||
* |
|
||||||
* Extended to support inline citation links based on the CSL. |
|
||||||
* |
|
||||||
* @BibCiteProcessor( |
|
||||||
* id = "citeproc-php", |
|
||||||
* label = @Translation("Citeproc PHP"), |
|
||||||
* ) |
|
||||||
*/ |
|
||||||
class CiteprocPhpInline extends BibCiteProcessorBase implements BibCiteProcessorInterface, ContainerFactoryPluginInterface { |
|
||||||
|
|
||||||
/** |
|
||||||
* Config factory service. |
|
||||||
* |
|
||||||
* @var \Drupal\Core\Config\ConfigFactoryInterface |
|
||||||
*/ |
|
||||||
protected $configFactory; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { |
|
||||||
return new static( |
|
||||||
$configuration, |
|
||||||
$plugin_id, |
|
||||||
$plugin_definition, |
|
||||||
$container->get('config.factory') |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory) { |
|
||||||
parent::__construct($configuration, $plugin_id, $plugin_definition); |
|
||||||
|
|
||||||
$this->configFactory = $config_factory; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getDescription() { |
|
||||||
return $this->t('Render citation by citeproc-php library'); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function render($data, $csl, $lang) { |
|
||||||
$cite_proc = new CiteProc($csl, $lang); |
|
||||||
$mode = !empty($data['mode']) ? $data['mode'] : NULL; |
|
||||||
|
|
||||||
if (!$data instanceof \stdClass) { |
|
||||||
$data = json_decode(json_encode($data)); |
|
||||||
} |
|
||||||
if (!empty($data)) { |
|
||||||
return $cite_proc->render($data, $mode); |
|
||||||
} |
|
||||||
return ''; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,54 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
namespace Drupal\footnotes\Plugin\CKEditorPlugin; |
|
||||||
|
|
||||||
use Drupal\ckeditor\CKEditorPluginBase; |
|
||||||
use Drupal\editor\Entity\Editor; |
|
||||||
use Drupal\Core\StringTranslation\StringTranslationTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* Defines the "Footnotes" plugin. |
|
||||||
* |
|
||||||
* @CKEditorPlugin( |
|
||||||
* id = "footnotes", |
|
||||||
* label = @Translation("FootnotesButton") |
|
||||||
* ) |
|
||||||
*/ |
|
||||||
class Footnotes extends CKEditorPluginBase { |
|
||||||
|
|
||||||
use StringTranslationTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getDependencies(Editor $editor) { |
|
||||||
return ['fakeobjects']; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getFile() { |
|
||||||
return drupal_get_path('module', 'footnotes') . '/assets/js/ckeditor/plugin.js'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getButtons() { |
|
||||||
return [ |
|
||||||
'footnotes' => [ |
|
||||||
'label' => $this->t('Footnotes'), |
|
||||||
'image' => drupal_get_path('module', 'footnotes') . '/assets/js/ckeditor/icons/footnotes.png', |
|
||||||
], |
|
||||||
]; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getConfig(Editor $editor) { |
|
||||||
return []; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,78 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
namespace Drupal\bibcite_footnotes\Plugin\CKEditorPlugin; |
|
||||||
|
|
||||||
use Drupal\ckeditor\CKEditorPluginBase; |
|
||||||
use Drupal\editor\Entity\Editor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Defines the "reference_footnotes" plugin. |
|
||||||
* |
|
||||||
* NOTE: The plugin ID ('id' key) corresponds to the CKEditor plugin name. |
|
||||||
* It is the first argument of the CKEDITOR.plugins.add() function in the |
|
||||||
* plugin.js file. |
|
||||||
* |
|
||||||
* @CKEditorPlugin( |
|
||||||
* id = "reference_footnotes", |
|
||||||
* label = @Translation("Reference Footnotes") |
|
||||||
* ) |
|
||||||
*/ |
|
||||||
class ReferenceFootnotes extends CKEditorPluginBase { |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
* |
|
||||||
* NOTE: The keys of the returned array corresponds to the CKEditor button |
|
||||||
* names. They are the first argument of the editor.ui.addButton() or |
|
||||||
* editor.ui.addRichCombo() functions in the plugin.js file. |
|
||||||
*/ |
|
||||||
public function getButtons() { |
|
||||||
// Make sure that the path to the image matches the file structure of |
|
||||||
// the CKEditor plugin you are implementing. |
|
||||||
return [ |
|
||||||
'reference_footnotes' => [ |
|
||||||
'label' => t('Reference Footnotes'), |
|
||||||
'image' => \Drupal::service('extension.list.module')->getPath('bibcite_footnotes') . |
|
||||||
'/js/plugins/reference_footnotes/images/icon.png', |
|
||||||
], |
|
||||||
]; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getFile() { |
|
||||||
// Make sure that the path to the plugin.js matches the file structure of |
|
||||||
// the CKEditor plugin you are implementing. |
|
||||||
return \Drupal::service('extension.list.module')->getPath('bibcite_footnotes') . '/js/plugins/reference_footnotes/plugin.js'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function isInternal() { |
|
||||||
return FALSE; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getDependencies(Editor $editor) { |
|
||||||
return ['fakeobjects']; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getLibraries(Editor $editor) { |
|
||||||
return []; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getConfig(Editor $editor) { |
|
||||||
return []; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,378 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
namespace Drupal\footnotes\Plugin\Filter; |
|
||||||
|
|
||||||
use Drupal\Component\Utility\Xss; |
|
||||||
use Drupal\Core\Form\FormStateInterface; |
|
||||||
use Drupal\Core\StringTranslation\StringTranslationTrait; |
|
||||||
use Drupal\filter\FilterProcessResult; |
|
||||||
use Drupal\filter\Plugin\FilterBase; |
|
||||||
|
|
||||||
/** |
|
||||||
* Provides a base filter for Footnotes filter. |
|
||||||
* |
|
||||||
* @Filter( |
|
||||||
* id = "filter_footnotes", |
|
||||||
* module = "footnotes", |
|
||||||
* title = @Translation("Footnotes filter"), |
|
||||||
* description = @Translation("You can insert footnotes directly into texts."), |
|
||||||
* type = \Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE, |
|
||||||
* cache = FALSE, |
|
||||||
* settings = { |
|
||||||
* "footnotes_collapse" = FALSE, |
|
||||||
* "footnotes_html" = FALSE |
|
||||||
* }, |
|
||||||
* weight = 0 |
|
||||||
* ) |
|
||||||
*/ |
|
||||||
class FootnotesFilter extends FilterBase { |
|
||||||
|
|
||||||
use StringTranslationTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* The renderer. |
|
||||||
* |
|
||||||
* @var \Drupal\Core\Render\RendererInterface |
|
||||||
*/ |
|
||||||
protected $renderer; |
|
||||||
|
|
||||||
/** |
|
||||||
* Constructs a FootnotesFilter object. |
|
||||||
* |
|
||||||
* @param array $configuration |
|
||||||
* A configuration array containing information about the plugin instance. |
|
||||||
* @param string $plugin_id |
|
||||||
* The plugin_id for the plugin instance. |
|
||||||
* @param array $plugin_definition |
|
||||||
* The plugin implementation definition. |
|
||||||
*/ |
|
||||||
public function __construct(array $configuration, $plugin_id, array $plugin_definition) { |
|
||||||
parent::__construct($configuration, $plugin_id, $plugin_definition); |
|
||||||
$this->renderer = \Drupal::service('renderer'); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get the tips for the filter. |
|
||||||
* |
|
||||||
* @param bool $long |
|
||||||
* If get the long or short tip. |
|
||||||
* |
|
||||||
* @return string |
|
||||||
* The tip to show for the user. |
|
||||||
*/ |
|
||||||
public function tips($long = FALSE) { |
|
||||||
if ($long) { |
|
||||||
return $this->t('You can insert footnotes directly into texts with <code>[fn]This text becomes a footnote.[/fn]</code>. This will be replaced with a running number (the footnote reference) and the text within the [fn] tags will be moved to the bottom of the page (the footnote). See <a href=":link">Footnotes Readme page</a> for additional usage options.', [':link' => 'http://drupal.org/project/footnotes">']); |
|
||||||
} |
|
||||||
else { |
|
||||||
return $this->t('Use [fn]...[/fn] (or <fn>...</fn>) to insert automatically numbered footnotes.'); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function process($text, $langcode) { |
|
||||||
// Supporting both [fn] and <fn> now. Thanks to fletchgqc |
|
||||||
// http://drupal.org/node/268026. |
|
||||||
// Convert all square brackets to angle brackets. This way all further code |
|
||||||
// just manipulates angle brackets. (Angle brackets are preferred here for |
|
||||||
// the simple reason that square brackets are more tedious to use in |
|
||||||
// regexps). |
|
||||||
if (is_array($text)) { |
|
||||||
implode($text); |
|
||||||
} |
|
||||||
$text = preg_replace('|\[fn([^\]]*)\]|', '<fn$1>', $text); |
|
||||||
$text = preg_replace('|\[/fn\]|', '</fn>', $text); |
|
||||||
$text = preg_replace('|\[footnotes([^\]]*)\]|', '<footnotes$1>', $text); |
|
||||||
|
|
||||||
// Check that there are an even number of open and closing tags. |
|
||||||
// If there is one closing tag missing, append this to the end. |
|
||||||
// If there is more disparity, throw a warning and continue. |
|
||||||
// A closing tag may sometimes be missing when we are processing a teaser |
|
||||||
// and it has been cut in the middle of the footnote. |
|
||||||
// See http://drupal.org/node/253326 |
|
||||||
$foo = []; |
|
||||||
$open_tags = preg_match_all("|<fn([^>]*)>|", $text, $foo); |
|
||||||
$close_tags = preg_match_all("|</fn>|", $text, $foo); |
|
||||||
|
|
||||||
if ($open_tags == $close_tags + 1) { |
|
||||||
$text = $text . '</fn>'; |
|
||||||
} |
|
||||||
elseif ($open_tags > $close_tags + 1) { |
|
||||||
trigger_error($this->t("You have unclosed fn tags. This is invalid and will |
|
||||||
produce unpredictable results.")); |
|
||||||
} |
|
||||||
|
|
||||||
// Before doing the replacement, the callback function needs to know which |
|
||||||
// options to use. |
|
||||||
$this->replaceCallback($this->settings, 'prepare'); |
|
||||||
|
|
||||||
$pattern = '|<fn([^>]*)>(.*?)</fn>|s'; |
|
||||||
$text = preg_replace_callback($pattern, [ |
|
||||||
$this, |
|
||||||
'replaceCallback', |
|
||||||
], $text); |
|
||||||
|
|
||||||
// Replace tag <footnotes> with the list of footnotes. |
|
||||||
// If tag is not present, by default add the footnotes at the end. |
|
||||||
// Thanks to acp on drupal.org for this idea. see |
|
||||||
// http://drupal.org/node/87226. |
|
||||||
$footer = $this->replaceCallback(NULL, 'output footer'); |
|
||||||
$pattern = '|(<footnotes([\ \/]*)>)|'; |
|
||||||
if (preg_match($pattern, $text) > 0) { |
|
||||||
$text = preg_replace($pattern, $footer, $text, 1); |
|
||||||
} |
|
||||||
elseif (!empty($footer)) { |
|
||||||
$text .= "\n\n" . $footer; |
|
||||||
} |
|
||||||
$result = new FilterProcessResult($text); |
|
||||||
$result->setAttachments([ |
|
||||||
'library' => [ |
|
||||||
'footnotes/footnotes', |
|
||||||
], |
|
||||||
]); |
|
||||||
return $result; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Helper function called from preg_replace_callback() above. |
|
||||||
* |
|
||||||
* Uses static vars to temporarily store footnotes found. |
|
||||||
* This is not threadsafe, but PHP isn't. |
|
||||||
* |
|
||||||
* @param mixed $matches |
|
||||||
* Elements from array: |
|
||||||
* - 0: complete matched string. |
|
||||||
* - 1: tag name. |
|
||||||
* - 2: tag attributes. |
|
||||||
* - 3: tag content. |
|
||||||
* @param string $op |
|
||||||
* Operation. |
|
||||||
* |
|
||||||
* @return string |
|
||||||
* Return the string processed by geshi library. |
|
||||||
*/ |
|
||||||
protected function replaceCallback($matches, $op = '') { |
|
||||||
static $opt_collapse = 0; |
|
||||||
static $opt_html = 0; |
|
||||||
static $n = 0; |
|
||||||
static $store_matches = []; |
|
||||||
static $used_values = []; |
|
||||||
$str = ''; |
|
||||||
|
|
||||||
if ($op == 'prepare') { |
|
||||||
// In the 'prepare' case, the first argument contains the options to use. |
|
||||||
// The name 'matches' is incorrect, we just use the variable anyway. |
|
||||||
$opt_collapse = $matches['footnotes_collapse']; |
|
||||||
$opt_html = $matches['footnotes_html']; |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
if ($op == 'output footer') { |
|
||||||
if (count($store_matches) > 0) { |
|
||||||
// Only if there are stored fn matches, pass the array of fns to be |
|
||||||
// themed as a list Drupal 7 requires we use "render element" which |
|
||||||
// just introduces a wrapper around the old array. |
|
||||||
// @FIXME |
|
||||||
// theme() has been renamed to _theme() and should NEVER be called |
|
||||||
// directly. Calling _theme() directly can alter the expected output and |
|
||||||
// potentially introduce security issues |
|
||||||
// (see https://www.drupal.org/node/2195739). You should use renderable |
|
||||||
// arrays instead. @see https://www.drupal.org/node/2195739 |
|
||||||
$markup = [ |
|
||||||
'#theme' => 'footnote_list', |
|
||||||
'#footnotes' => $store_matches, |
|
||||||
]; |
|
||||||
$str = $this->renderer->render($markup); |
|
||||||
} |
|
||||||
// Reset the static variables so they can be used again next time. |
|
||||||
$n = 0; |
|
||||||
$store_matches = []; |
|
||||||
$used_values = []; |
|
||||||
|
|
||||||
return $str; |
|
||||||
} |
|
||||||
|
|
||||||
// Default op: act as called by preg_replace_callback() |
|
||||||
// Random string used to ensure footnote id's are unique, even |
|
||||||
// when contents of multiple nodes reside on same page. |
|
||||||
// (fixes http://drupal.org/node/194558). |
|
||||||
$randstr = $this->randstr(); |
|
||||||
|
|
||||||
$value = ''; |
|
||||||
// Did the pattern match anything in the <fn> tag? |
|
||||||
if ($matches[1]) { |
|
||||||
// See if value attribute can parsed, either well-formed in quotes eg |
|
||||||
// <fn value="3">. |
|
||||||
if (preg_match('|value=["\'](.*?)["\']|', $matches[1], $value_match)) { |
|
||||||
$value = $value_match[1]; |
|
||||||
// Or without quotes eg <fn value=8>. |
|
||||||
} |
|
||||||
elseif (preg_match('|value=(\S*)|', $matches[1], $value_match)) { |
|
||||||
$value = $value_match[1]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if ($value) { |
|
||||||
// A value label was found. If it is numeric, record it in $n so further |
|
||||||
// notes can increment from there. |
|
||||||
// After adding support for multiple references to same footnote in the |
|
||||||
// body (http://drupal.org/node/636808) also must check that $n is |
|
||||||
// monotonously increasing. |
|
||||||
if (is_numeric($value) && $n < $value) { |
|
||||||
$n = $value; |
|
||||||
} |
|
||||||
} |
|
||||||
elseif ($opt_collapse and $value_existing = $this->findFootnote($matches[2], $store_matches)) { |
|
||||||
// An identical footnote already exists. Set value to the previously |
|
||||||
// existing value. |
|
||||||
$value = $value_existing; |
|
||||||
} |
|
||||||
else { |
|
||||||
// No value label, either a plain <fn> or unparsable attributes. Increment |
|
||||||
// the footnote counter, set label equal to it. |
|
||||||
$n++; |
|
||||||
$value = $n; |
|
||||||
} |
|
||||||
|
|
||||||
// Remove illegal characters from $value so it can be used as an HTML id |
|
||||||
// attribute. |
|
||||||
$value_id = preg_replace('|[^\w\-]|', '', $value); |
|
||||||
|
|
||||||
// Create a sanitized version of $text that is suitable for using as HTML |
|
||||||
// attribute value. (In particular, as the title attribute to the footnote |
|
||||||
// link). |
|
||||||
$allowed_tags = []; |
|
||||||
$text_clean = Xss::filter($matches['2'], $allowed_tags); |
|
||||||
// HTML attribute cannot contain quotes. |
|
||||||
$text_clean = str_replace('"', """, $text_clean); |
|
||||||
// Remove newlines. Browsers don't support them anyway and they'll confuse |
|
||||||
// line break converter in filter.module. |
|
||||||
$text_clean = str_replace("\n", " ", $text_clean); |
|
||||||
$text_clean = str_replace("\r", "", $text_clean); |
|
||||||
|
|
||||||
// Create a footnote item as an array. |
|
||||||
$fn = [ |
|
||||||
'value' => $value, |
|
||||||
'text' => $opt_html ? html_entity_decode($matches[2]) : $matches[2], |
|
||||||
'text_clean' => $text_clean, |
|
||||||
'fn_id' => 'footnote' . $value_id . '_' . $randstr, |
|
||||||
'ref_id' => 'footnoteref' . $value_id . '_' . $randstr, |
|
||||||
]; |
|
||||||
|
|
||||||
// We now allow to repeat the footnote value label, in which case the link |
|
||||||
// to the previously existing footnote is returned. Content of the current |
|
||||||
// footnote is ignored. See http://drupal.org/node/636808 . |
|
||||||
if (!in_array($value, $used_values)) { |
|
||||||
// This is the normal case, add the footnote to $store_matches. |
|
||||||
// Store the footnote item. |
|
||||||
array_push($store_matches, $fn); |
|
||||||
array_push($used_values, $value); |
|
||||||
} |
|
||||||
else { |
|
||||||
// A footnote with the same label already exists. |
|
||||||
// Use the text and id from the first footnote with this value. |
|
||||||
// Any text in this footnote is discarded. |
|
||||||
$i = array_search($value, $used_values); |
|
||||||
$fn['text'] = $store_matches[$i]['text']; |
|
||||||
$fn['text_clean'] = $store_matches[$i]['text_clean']; |
|
||||||
$fn['fn_id'] = $store_matches[$i]['fn_id']; |
|
||||||
// Push the new ref_id into the first occurrence of this footnote label |
|
||||||
// The stored footnote thus holds a list of ref_id's rather than just one |
|
||||||
// id. |
|
||||||
$ref_array = is_array($store_matches[$i]['ref_id']) ? $store_matches[$i]['ref_id'] : [$store_matches[$i]['ref_id']]; |
|
||||||
array_push($ref_array, $fn['ref_id']); |
|
||||||
$store_matches[$i]['ref_id'] = $ref_array; |
|
||||||
} |
|
||||||
|
|
||||||
// Return the item themed into a footnote link. |
|
||||||
// Drupal 7 requires we use "render element" which just introduces a wrapper |
|
||||||
// around the old array. |
|
||||||
$fn = [ |
|
||||||
'#theme' => 'footnote_link', |
|
||||||
'#fn' => $fn, |
|
||||||
]; |
|
||||||
$result = $this->renderer->render($fn); |
|
||||||
|
|
||||||
return $result; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Helper function to return a random text string. |
|
||||||
* |
|
||||||
* @return string |
|
||||||
* Random (lowercase) alphanumeric string. |
|
||||||
*/ |
|
||||||
public function randstr() { |
|
||||||
$chars = "abcdefghijklmnopqrstuwxyz1234567890"; |
|
||||||
$str = ""; |
|
||||||
|
|
||||||
// Seeding with srand() not necessary in modern PHP versions. |
|
||||||
for ($i = 0; $i < 7; $i++) { |
|
||||||
$n = rand(0, strlen($chars) - 1); |
|
||||||
$str .= substr($chars, $n, 1); |
|
||||||
} |
|
||||||
return $str; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Create the settings form for the filter. |
|
||||||
* |
|
||||||
* @param array $form |
|
||||||
* A minimally prepopulated form array. |
|
||||||
* @param \Drupal\Core\Form\FormStateInterface $form_state |
|
||||||
* The state of the (entire) configuration form. |
|
||||||
* |
|
||||||
* @return array |
|
||||||
* The $form array with additional form elements for the settings of |
|
||||||
* this filter. The submitted form values should match $this->settings. |
|
||||||
* |
|
||||||
* @todo Add validation of submited form values, it already exists for |
|
||||||
* drupal 7, must update it only. |
|
||||||
*/ |
|
||||||
public function settingsForm(array $form, FormStateInterface $form_state) { |
|
||||||
$settings['footnotes_collapse'] = [ |
|
||||||
'#type' => 'checkbox', |
|
||||||
'#title' => $this->t('Collapse footnotes with identical content'), |
|
||||||
'#default_value' => $this->settings['footnotes_collapse'], |
|
||||||
'#description' => $this->t('If two footnotes have the exact same content, they will be collapsed into one as if using the same value="" attribute.'), |
|
||||||
]; |
|
||||||
$settings['footnotes_html'] = [ |
|
||||||
'#type' => 'checkbox', |
|
||||||
'#title' => $this->t('Handle footnote text as HTML'), |
|
||||||
'#default_value' => $this->settings['footnotes_html'], |
|
||||||
'#description' => $this->t('If not checked, a HTML tag in the footnote text will be shown as-is to the user.'), |
|
||||||
]; |
|
||||||
return $settings; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Search the $store_matches array for footnote text that matches. |
|
||||||
* |
|
||||||
* Note: This does a linear search on the $store_matches array. For a large |
|
||||||
* list of footnotes it would be more efficient to maintain a separate array |
|
||||||
* with the footnote content as key, in order to do a hash lookup at this |
|
||||||
* stage. Since you typically only have a handful of footnotes, this simple |
|
||||||
* search is assumed to be more efficient, but was not tested. |
|
||||||
* |
|
||||||
* @param string $text |
|
||||||
* The footnote text. |
|
||||||
* @param array $store_matches |
|
||||||
* The matches array. |
|
||||||
* |
|
||||||
* @return string|false |
|
||||||
* The value of the existing footnote, FALSE otherwise. |
|
||||||
*/ |
|
||||||
private function findFootnote($text, array &$store_matches) { |
|
||||||
if (!empty($store_matches)) { |
|
||||||
foreach ($store_matches as &$fn) { |
|
||||||
if ($fn['text'] == $text) { |
|
||||||
return $fn['value']; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return FALSE; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,300 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Drupal\bibcite_footnotes\Plugin\Filter; |
|
||||||
|
|
||||||
use Drupal\Component\Utility\Xss; |
|
||||||
use Drupal\Core\Config\Config; |
|
||||||
use Drupal\Core\Config\ConfigFactoryInterface; |
|
||||||
use Drupal\Core\Config\ImmutableConfig; |
|
||||||
use Drupal\Core\Form\FormStateInterface; |
|
||||||
use Drupal\Core\Render\RendererInterface; |
|
||||||
use Drupal\filter\FilterProcessResult; |
|
||||||
use Drupal\filter\Plugin\FilterBase; |
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface; |
|
||||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* Reference Footnotes filter. |
|
||||||
* |
|
||||||
* @Filter( |
|
||||||
* id = "filter_reference_footnotes", |
|
||||||
* title = @Translation("Reference Footnotes filter"), |
|
||||||
* description = @Translation("You can insert footnotes directly into texts."), |
|
||||||
* type = \Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE, |
|
||||||
* cache = FALSE, |
|
||||||
* settings = { |
|
||||||
* "footnotes_collapse" = FALSE, |
|
||||||
* "footnotes_ibid" = FALSE, |
|
||||||
* "notes_section_label" = "Notes", |
|
||||||
* "reference_dont_show_backlink_text" = FALSE, |
|
||||||
* "works_cited_sort_by" = "weight" |
|
||||||
* }, |
|
||||||
* weight = 0 |
|
||||||
* ) |
|
||||||
*/ |
|
||||||
final class ReferenceFootnotesFilter extends FilterBase implements ContainerFactoryPluginInterface { |
|
||||||
|
|
||||||
protected RendererInterface $renderer; |
|
||||||
|
|
||||||
protected ImmutableConfig $config; |
|
||||||
|
|
||||||
protected Config $configEditable; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
array $configuration, |
|
||||||
string $plugin_id, |
|
||||||
array $plugin_definition, |
|
||||||
RendererInterface $renderer, |
|
||||||
ConfigFactoryInterface $configFactory, |
|
||||||
) { |
|
||||||
parent::__construct($configuration, $plugin_id, $plugin_definition); |
|
||||||
|
|
||||||
$this->renderer = $renderer; |
|
||||||
$this->config = $configFactory->get('reference_footnotes.settings'); |
|
||||||
$this->configEditable = $configFactory->getEditable('reference_footnotes.settings'); |
|
||||||
} |
|
||||||
|
|
||||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self { |
|
||||||
return new self( |
|
||||||
$configuration, |
|
||||||
(string) $plugin_id, |
|
||||||
$plugin_definition, |
|
||||||
$container->get('renderer'), |
|
||||||
$container->get('config.factory'), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
public function settingsForm(array $form, FormStateInterface $form_state): array { |
|
||||||
$settings['footnotes_collapse'] = [ |
|
||||||
'#type' => 'checkbox', |
|
||||||
'#title' => $this->t('Collapse reference footnotes with identical content'), |
|
||||||
'#default_value' => (bool) ($this->settings['footnotes_collapse'] ?? FALSE), |
|
||||||
'#description' => $this->t('If two reference footnotes have the exact same content, they will be collapsed into one as if using the same value="" attribute.'), |
|
||||||
]; |
|
||||||
|
|
||||||
$settings['footnotes_ibid'] = [ |
|
||||||
'#type' => 'checkbox', |
|
||||||
'#title' => $this->t('Display subsequent instances of multiple references with \'Ibid.\''), |
|
||||||
'#default_value' => (bool) ($this->settings['footnotes_ibid'] ?? FALSE), |
|
||||||
]; |
|
||||||
|
|
||||||
$settings['notes_section_label'] = [ |
|
||||||
'#type' => 'textfield', |
|
||||||
'#title' => $this->t('Notes section heading label'), |
|
||||||
'#default_value' => (string) ($this->settings['notes_section_label'] ?? 'Notes'), |
|
||||||
]; |
|
||||||
|
|
||||||
$settings['reference_dont_show_backlink_text'] = [ |
|
||||||
'#type' => 'checkbox', |
|
||||||
'#title' => $this->t("Don't show note 'value' text in reference list."), |
|
||||||
'#description' => $this->t("Suitable for MLA-style citations, like (Smith, 33-22)"), |
|
||||||
'#default_value' => (bool) ($this->settings['reference_dont_show_backlink_text'] ?? FALSE), |
|
||||||
]; |
|
||||||
|
|
||||||
$settings['works_cited_sort_by'] = [ |
|
||||||
'#type' => 'select', |
|
||||||
'#title' => $this->t('Sort Works Cited list by'), |
|
||||||
'#options' => [ |
|
||||||
'weight' => $this->t('Manually'), |
|
||||||
'alphabetical' => $this->t('Alphabetically'), |
|
||||||
], |
|
||||||
'#default_value' => (string) ($this->settings['works_cited_sort_by'] ?? 'weight'), |
|
||||||
]; |
|
||||||
|
|
||||||
return $settings; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Helper function called from preg_replace_callback(). |
|
||||||
* |
|
||||||
* Uses static vars to temporarily store footnotes found. |
|
||||||
* This is not threadsafe, but PHP isn't. |
|
||||||
*/ |
|
||||||
protected function replaceCallback(array $matches, string $op = ''): string|int { |
|
||||||
static $opt_collapse = 0; |
|
||||||
static $n = 0; |
|
||||||
static $store_matches = []; |
|
||||||
static $used_values = []; |
|
||||||
|
|
||||||
if ($op === 'prepare') { |
|
||||||
// In the 'prepare' case, $matches contains the options to use. |
|
||||||
$opt_collapse = !empty($matches['footnotes_collapse']); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
if ($op === 'output footer') { |
|
||||||
$str = ''; |
|
||||||
|
|
||||||
if (count($store_matches) > 0) { |
|
||||||
if (!empty($this->settings['footnotes_ibid'])) { |
|
||||||
$this->ibidemify($store_matches); |
|
||||||
} |
|
||||||
|
|
||||||
$markup = [ |
|
||||||
'#theme' => 'bibcite_footnote_list', |
|
||||||
'#notes' => $store_matches, |
|
||||||
'#config' => $this->settings, |
|
||||||
]; |
|
||||||
$str = (string) $this->renderer->render($markup, FALSE); |
|
||||||
} |
|
||||||
|
|
||||||
// Reset static variables. |
|
||||||
$n = 0; |
|
||||||
$store_matches = []; |
|
||||||
$used_values = []; |
|
||||||
|
|
||||||
return $str; |
|
||||||
} |
|
||||||
|
|
||||||
// Default op: act as called by preg_replace_callback(). |
|
||||||
$randstr = $this->randstr(); |
|
||||||
|
|
||||||
$value = $this->extractAttribute($matches, 'value'); |
|
||||||
$page = $this->extractAttribute($matches, 'page'); |
|
||||||
$reference = $this->extractAttribute($matches, 'reference'); |
|
||||||
|
|
||||||
if ($value !== '') { |
|
||||||
if (is_numeric($value) && $n < (int) $value) { |
|
||||||
$n = (int) $value; |
|
||||||
} |
|
||||||
} |
|
||||||
elseif ($opt_collapse && ($value_existing = $this->findFootnote($matches[2], $reference, $store_matches)) !== FALSE) { |
|
||||||
$value = (string) $value_existing; |
|
||||||
} |
|
||||||
else { |
|
||||||
$n++; |
|
||||||
$value = (string) $n; |
|
||||||
} |
|
||||||
|
|
||||||
$value_id = preg_replace('|[^\w\-]|', '', $value) ?? ''; |
|
||||||
|
|
||||||
// Sanitize content for title attribute. |
|
||||||
$allowed_tags = []; |
|
||||||
$text_clean = Xss::filter($matches[2], $allowed_tags); |
|
||||||
$text_clean = str_replace('"', '"', $text_clean); |
|
||||||
$text_clean = str_replace("\n", ' ', $text_clean); |
|
||||||
$text_clean = str_replace("\r", '', $text_clean); |
|
||||||
|
|
||||||
$fn = [ |
|
||||||
'value' => $value, |
|
||||||
'text' => $matches[2], |
|
||||||
'text_clean' => $text_clean, |
|
||||||
'page' => $page, |
|
||||||
'reference' => $reference, |
|
||||||
'fn_id' => 'footnote' . $value_id . '_' . $randstr, |
|
||||||
'ref_id' => 'footnoteref' . $value_id . '_' . $randstr, |
|
||||||
]; |
|
||||||
|
|
||||||
if (!in_array($value, $used_values, TRUE)) { |
|
||||||
$store_matches[] = $fn; |
|
||||||
$used_values[] = $value; |
|
||||||
} |
|
||||||
else { |
|
||||||
$i = array_search($value, $used_values, TRUE); |
|
||||||
$fn['text'] = $store_matches[$i]['text']; |
|
||||||
$fn['text_clean'] = $store_matches[$i]['text_clean']; |
|
||||||
$fn['fn_id'] = $store_matches[$i]['fn_id']; |
|
||||||
|
|
||||||
$ref_array = is_array($store_matches[$i]['ref_id']) ? $store_matches[$i]['ref_id'] : [$store_matches[$i]['ref_id']]; |
|
||||||
$ref_array[] = $fn['ref_id']; |
|
||||||
$store_matches[$i]['ref_id'] = $ref_array; |
|
||||||
} |
|
||||||
|
|
||||||
$render_array = [ |
|
||||||
'#theme' => 'bibcite_footnote_link', |
|
||||||
'fn' => $fn, |
|
||||||
]; |
|
||||||
|
|
||||||
return (string) $this->renderer->render($render_array, FALSE); |
|
||||||
} |
|
||||||
|
|
||||||
private function findFootnote(string $text, string $reference, array &$store_matches): string|false { |
|
||||||
foreach ($store_matches as $fn) { |
|
||||||
if (($fn['text'] ?? NULL) === $text && ($fn['reference'] ?? NULL) === $reference) { |
|
||||||
return (string) $fn['value']; |
|
||||||
} |
|
||||||
} |
|
||||||
return FALSE; |
|
||||||
} |
|
||||||
|
|
||||||
protected function extractAttribute(array $matches, string $attribute): string { |
|
||||||
$value = ''; |
|
||||||
if (!empty($matches[1])) { |
|
||||||
if (preg_match('|' . preg_quote($attribute, '|') . '=["\'](.*?)["\']|', $matches[1], $value_match)) { |
|
||||||
$value = $value_match[1]; |
|
||||||
} |
|
||||||
elseif (preg_match('|' . preg_quote($attribute, '|') . '=(\S*)|', $matches[1], $value_match)) { |
|
||||||
$value = $value_match[1]; |
|
||||||
} |
|
||||||
} |
|
||||||
return $value; |
|
||||||
} |
|
||||||
|
|
||||||
protected function ibidemify(array &$footnotes): void { |
|
||||||
$prev_reference_id = FALSE; |
|
||||||
foreach ($footnotes as $index => $fn) { |
|
||||||
if ($prev_reference_id && ($fn['reference'] ?? NULL) === $prev_reference_id) { |
|
||||||
$footnotes[$index]['ibid'] = TRUE; |
|
||||||
continue; |
|
||||||
} |
|
||||||
$prev_reference_id = $fn['reference'] ?? FALSE; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public function process($text, $langcode): FilterProcessResult { |
|
||||||
if (is_array($text)) { |
|
||||||
$text = implode('', $text); |
|
||||||
} |
|
||||||
|
|
||||||
$text = preg_replace('|\[fn([^\]]*)\]|', '<fn$1>', (string) $text); |
|
||||||
$text = preg_replace('|\[/fn\]|', '</fn>', (string) $text); |
|
||||||
$text = preg_replace('|\[footnotes([^\]]*)\]|', '<footnotes$1>', (string) $text); |
|
||||||
|
|
||||||
$foo = []; |
|
||||||
$open_tags = preg_match_all("|<fn([^>]*)>|", $text, $foo); |
|
||||||
$close_tags = preg_match_all("|</fn>|", $text, $foo); |
|
||||||
|
|
||||||
if ($open_tags === $close_tags + 1) { |
|
||||||
$text .= '</fn>'; |
|
||||||
} |
|
||||||
elseif ($open_tags > $close_tags + 1) { |
|
||||||
// Keep behavior, but avoid translating inside trigger_error message. |
|
||||||
trigger_error('You have unclosed fn tags. This is invalid and will produce unpredictable results.'); |
|
||||||
} |
|
||||||
|
|
||||||
// Let the callback know which options to use. |
|
||||||
$this->replaceCallback($this->settings, 'prepare'); |
|
||||||
|
|
||||||
$pattern = '|<fn([^>]*)>(.*?)</fn>|s'; |
|
||||||
$text = preg_replace_callback($pattern, [$this, 'replaceCallback'], $text); |
|
||||||
|
|
||||||
$footer = $this->replaceCallback([], 'output footer'); |
|
||||||
$pattern = '|(<footnotes([^\]]*)>)|'; |
|
||||||
|
|
||||||
if (preg_match($pattern, $text) > 0) { |
|
||||||
$text = preg_replace($pattern, (string) $footer, $text, 1); |
|
||||||
} |
|
||||||
elseif (!empty($footer)) { |
|
||||||
$text .= "\n\n" . $footer; |
|
||||||
} |
|
||||||
|
|
||||||
$result = new FilterProcessResult((string) $text); |
|
||||||
$result->setAttachments([ |
|
||||||
'library' => ['footnotes/footnotes'], |
|
||||||
]); |
|
||||||
return $result; |
|
||||||
} |
|
||||||
|
|
||||||
public function randstr(): string { |
|
||||||
$chars = 'abcdefghijklmnopqrstuwxyz1234567890'; |
|
||||||
$str = ''; |
|
||||||
for ($i = 0; $i < 7; $i++) { |
|
||||||
$n = rand(0, strlen($chars) - 1); |
|
||||||
$str .= substr($chars, $n, 1); |
|
||||||
} |
|
||||||
return $str; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,16 +0,0 @@ |
|||||||
{# |
|
||||||
/** |
|
||||||
* @file footnote-link.html.twig |
|
||||||
* Default theme implementation to present an inline reference footnote link. |
|
||||||
* |
|
||||||
* Available variables: |
|
||||||
* - fn: Components of the footnote |
|
||||||
* - link: Rendered link. |
|
||||||
* - attributes: HTML attributes for the container element. |
|
||||||
* |
|
||||||
* @see template_preprocess_footnote_link(). |
|
||||||
* |
|
||||||
* @ingroup themeable |
|
||||||
*/ |
|
||||||
#} |
|
||||||
{{ fn }} |
|
||||||
@ -1,21 +0,0 @@ |
|||||||
{# |
|
||||||
/** |
|
||||||
* @file footnote-list.html.twig |
|
||||||
* Default theme implementation to present a list of reference footnotes. |
|
||||||
* |
|
||||||
* Available variables: |
|
||||||
* - footnotess: A list of footnotes |
|
||||||
* - notes: A list of free-form notes |
|
||||||
* - references: A list of citations |
|
||||||
* - attributes: HTML attributes for the container element. |
|
||||||
* |
|
||||||
* @see template_preprocess_footnote_list(). |
|
||||||
* |
|
||||||
* @ingroup themeable |
|
||||||
*/ |
|
||||||
#} |
|
||||||
|
|
||||||
<div{{ attributes.addClass('footnote-list') }}> |
|
||||||
{{ notes }} |
|
||||||
{{ references }} |
|
||||||
</div> |
|
||||||
@ -1,2 +0,0 @@ |
|||||||
{# footnotes/footnote-link.html.twig #} |
|
||||||
<a class="see-footnote" id="{{ fn.ref_id }}" title="{{ fn.text_clean }}" href="#{{ fn.fn_id }}">{{ fn.value }}</a> |
|
||||||
@ -1,23 +0,0 @@ |
|||||||
{# footnotes/footnote-list.html.twig #} |
|
||||||
<ul class="footnotes"> |
|
||||||
{% for fn in footnotes %} |
|
||||||
{% if fn.ref_id is iterable %} |
|
||||||
{# |
|
||||||
// Output footnote that has more than one reference to it in the body. |
|
||||||
// The only difference is to insert backlinks to all references. |
|
||||||
// Helper: we need to enumerate a, b, c... |
|
||||||
#} |
|
||||||
{% set abc = "abcdefghijklmnopqrstuvwxyz"|split('') %} |
|
||||||
{% set i = 0 %} |
|
||||||
<li class="footnote" id="{{ fn.fn_id }}"><a href="#{{ fn.ref_id.0 }}" class="footnote-label">{{ fn.value }}</a> |
|
||||||
{% for ref in fn.ref_id %} |
|
||||||
<a class="footnote-multi" href="#{{ ref }}">{{ attribute(abc, i) }}</a> |
|
||||||
{% set i = i + 1 %} |
|
||||||
{% endfor %} |
|
||||||
{{ fn.text|raw }}</li> |
|
||||||
{% else %} |
|
||||||
{# Output normal footnote. #} |
|
||||||
<li class="footnote" id="{{ fn.fn_id }}"><a class="footnote-label" href="#{{ fn.ref_id }}">{{ fn.value }}</a>{{ fn.text|raw }}</li> |
|
||||||
{% endif %} |
|
||||||
{% endfor %} |
|
||||||
</ul> |
|
||||||
@ -1,168 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
namespace Drupal\Tests\footnotes\Functional; |
|
||||||
|
|
||||||
use Drupal\Core\Session\AccountInterface; |
|
||||||
use Drupal\Core\StringTranslation\StringTranslationTrait; |
|
||||||
use Drupal\Tests\BrowserTestBase; |
|
||||||
|
|
||||||
/** |
|
||||||
* Contains Footnotes Filter plugin functionality tests. |
|
||||||
* |
|
||||||
* @group footnotes |
|
||||||
*/ |
|
||||||
class FootnotesFilterPluginTest extends BrowserTestBase { |
|
||||||
|
|
||||||
use StringTranslationTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
protected static $modules = [ |
|
||||||
'fakeobjects', |
|
||||||
'footnotes', |
|
||||||
'node', |
|
||||||
]; |
|
||||||
|
|
||||||
/** |
|
||||||
* An user with permissions to proper permissions. |
|
||||||
* |
|
||||||
* @var \Drupal\user\UserInterface |
|
||||||
*/ |
|
||||||
protected $adminUser; |
|
||||||
|
|
||||||
/** |
|
||||||
* Text format name. |
|
||||||
* |
|
||||||
* @var string |
|
||||||
*/ |
|
||||||
protected $formatName; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
protected function setUp() { |
|
||||||
parent::setUp(); |
|
||||||
|
|
||||||
// Create a filter admin user. |
|
||||||
$permissions = [ |
|
||||||
'administer filters', |
|
||||||
'administer nodes', |
|
||||||
'access administration pages', |
|
||||||
'administer site configuration', |
|
||||||
]; |
|
||||||
$this->adminUser = $this->drupalCreateUser($permissions); |
|
||||||
$this->formatName = strtolower($this->randomMachineName()); |
|
||||||
|
|
||||||
$this->drupalLogin($this->adminUser); |
|
||||||
$this->createTextFormat(); |
|
||||||
$this->drupalCreateContentType(['type' => 'page']); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Tests CKEditor Filter plugin functionality. |
|
||||||
*/ |
|
||||||
public function testDefaultFunctionality() { |
|
||||||
// Verify a title with HTML entities is properly escaped. |
|
||||||
$text1 = 'This is the note one.'; |
|
||||||
$note1 = '[fn]' . $text1 . '[/fn]'; |
|
||||||
$text2 = 'And this is the note two.'; |
|
||||||
$note2 = "<fn>$text2</fn>"; |
|
||||||
|
|
||||||
$body = '<p>' . $this->randomMachineName(100) . $note1 . '</p><p>' . |
|
||||||
$this->randomMachineName(100) . $note2 . '</p>'; |
|
||||||
|
|
||||||
// Create a node. |
|
||||||
$node = $this->drupalCreateNode([ |
|
||||||
'title' => $this->randomString(), |
|
||||||
'body' => [ |
|
||||||
0 => [ |
|
||||||
'value' => $body, |
|
||||||
'format' => $this->formatName, |
|
||||||
], |
|
||||||
], |
|
||||||
]); |
|
||||||
|
|
||||||
$this->drupalGet('node/' . $node->id()); |
|
||||||
|
|
||||||
// Footnote with [fn]. |
|
||||||
$this->assertNoRaw($note1); |
|
||||||
$this->assertText($text1); |
|
||||||
|
|
||||||
// Footnote with <fn>. |
|
||||||
$this->assertNoRaw($note2); |
|
||||||
$this->assertText($text2); |
|
||||||
|
|
||||||
// Css file: |
|
||||||
$this->assertRaw('/assets/css/footnotes.css'); |
|
||||||
// @todo currently additional settings doesn't work as expected. |
|
||||||
// So we don't check additional settings for now. |
|
||||||
// $this->createTextFormat(TRUE); |
|
||||||
$text1 = 'This is the note one.'; |
|
||||||
$note1 = "[fn value='1']{$text1}[/fn]"; |
|
||||||
$text2 = 'And this is the note two.'; |
|
||||||
$note2 = "<fn value='1'>{$text2}</fn>"; |
|
||||||
|
|
||||||
$body = '<p>' . $this->randomMachineName(100) . $note1 . '</p><p>' . |
|
||||||
$this->randomMachineName(100) . $note2 . '</p>'; |
|
||||||
|
|
||||||
// Create a node. |
|
||||||
$node = $this->drupalCreateNode([ |
|
||||||
'title' => $this->randomString(), |
|
||||||
'body' => [ |
|
||||||
0 => [ |
|
||||||
'value' => $body, |
|
||||||
'format' => $this->formatName, |
|
||||||
], |
|
||||||
], |
|
||||||
]); |
|
||||||
|
|
||||||
$this->drupalGet('node/' . $node->id()); |
|
||||||
|
|
||||||
// Footnote with [fn]. |
|
||||||
$this->assertNoRaw($note1); |
|
||||||
$this->assertText($text1); |
|
||||||
|
|
||||||
// Elements with the same value should be collapsed. |
|
||||||
// @todo This should work only if footnotes_collapse setting is enabled. |
|
||||||
$this->assertNoRaw($note2); |
|
||||||
$this->assertNoText($text2); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Create a new text format. |
|
||||||
* |
|
||||||
* @param bool $additional_settings |
|
||||||
* Indicates if filter settings should be enabled. |
|
||||||
*/ |
|
||||||
protected function createTextFormat($additional_settings = FALSE) { |
|
||||||
$button_groups = json_encode([ |
|
||||||
[ |
|
||||||
[ |
|
||||||
'name' => 'Tools', |
|
||||||
'items' => ['Source', 'footnotes'], |
|
||||||
], |
|
||||||
], |
|
||||||
]); |
|
||||||
|
|
||||||
$edit = [ |
|
||||||
'format' => $this->formatName, |
|
||||||
'name' => $this->formatName, |
|
||||||
'roles[' . AccountInterface::AUTHENTICATED_ROLE . ']' => TRUE, |
|
||||||
'editor[editor]' => 'ckeditor', |
|
||||||
'filters[filter_footnotes][status]' => TRUE, |
|
||||||
]; |
|
||||||
$this->drupalGet("admin/config/content/formats/add"); |
|
||||||
// Keep the "CKEditor" editor selected and click the "Configure" button. |
|
||||||
$this->drupalPostForm(NULL, $edit, 'editor_configure'); |
|
||||||
$edit['editor[settings][toolbar][button_groups]'] = $button_groups; |
|
||||||
$edit['filters[filter_footnotes][settings][footnotes_collapse]'] = $button_groups; |
|
||||||
if ($additional_settings) { |
|
||||||
$edit['filters[filter_footnotes][settings][footnotes_collapse]'] = 1; |
|
||||||
$edit['filters[filter_footnotes][settings][footnotes_html]'] = 1; |
|
||||||
} |
|
||||||
$this->drupalPostForm(NULL, $edit, $this->t('Save configuration')); |
|
||||||
$this->assertText($this->t('Added text format @format.', ['@format' => $this->formatName])); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,176 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
namespace Drupal\Tests\footnotes\FunctionalJavascript; |
|
||||||
|
|
||||||
use Drupal\Core\Entity\Entity\EntityFormDisplay; |
|
||||||
use Drupal\Core\StringTranslation\StringTranslationTrait; |
|
||||||
use Drupal\editor\Entity\Editor; |
|
||||||
use Drupal\field\Entity\FieldConfig; |
|
||||||
use Drupal\field\Entity\FieldStorageConfig; |
|
||||||
use Drupal\filter\Entity\FilterFormat; |
|
||||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase; |
|
||||||
use Drupal\node\Entity\NodeType; |
|
||||||
use Drupal\Tests\ckeditor\Traits\CKEditorTestTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* Contains Footnotes CKEditor plugin functionality tests. |
|
||||||
* |
|
||||||
* @group footnotes |
|
||||||
*/ |
|
||||||
class FootnotesCkeditorPluginTest extends WebDriverTestBase |
|
||||||
{ |
|
||||||
|
|
||||||
use StringTranslationTrait; |
|
||||||
use CKEditorTestTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
protected $defaultTheme = 'stark'; |
|
||||||
|
|
||||||
/** |
|
||||||
* The account. |
|
||||||
* |
|
||||||
* @var \Drupal\user\UserInterface |
|
||||||
*/ |
|
||||||
protected $account; |
|
||||||
|
|
||||||
/** |
|
||||||
* The FilterFormat config entity used for testing. |
|
||||||
* |
|
||||||
* @var \Drupal\filter\FilterFormatInterface |
|
||||||
*/ |
|
||||||
protected $filterFormat; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public static $modules = ['node', 'ckeditor', 'filter', 'ckeditor_test', 'fakeobjects', 'footnotes']; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
protected function setUp() |
|
||||||
{ |
|
||||||
parent::setUp(); |
|
||||||
|
|
||||||
// Create a text format and associate CKEditor. |
|
||||||
$this->filterFormat = FilterFormat::create([ |
|
||||||
'format' => 'filtered_html', |
|
||||||
'name' => 'Filtered HTML', |
|
||||||
'filters' => [ |
|
||||||
'filter_footnotes' => [ |
|
||||||
'status' => TRUE, |
|
||||||
'settings' => [ |
|
||||||
'footnotes_collapse' => 0, |
|
||||||
'footnotes_html' => 0 |
|
||||||
], |
|
||||||
], |
|
||||||
], |
|
||||||
]); |
|
||||||
$this->filterFormat->save(); |
|
||||||
|
|
||||||
Editor::create([ |
|
||||||
'format' => 'filtered_html', |
|
||||||
'editor' => 'ckeditor', |
|
||||||
'settings' => [ |
|
||||||
'toolbar' => [ |
|
||||||
'rows' => [ |
|
||||||
[ |
|
||||||
[ |
|
||||||
'name' => 'All the things', |
|
||||||
'items' => [ |
|
||||||
'Source', |
|
||||||
'Bold', |
|
||||||
'Italic', |
|
||||||
'footnotes', |
|
||||||
], |
|
||||||
], |
|
||||||
], |
|
||||||
], |
|
||||||
], |
|
||||||
], |
|
||||||
])->save(); |
|
||||||
|
|
||||||
// Create a node type for testing. |
|
||||||
NodeType::create(['type' => 'page', 'name' => 'page'])->save(); |
|
||||||
|
|
||||||
$field_storage = FieldStorageConfig::loadByName('node', 'body'); |
|
||||||
|
|
||||||
// Create a body field instance for the 'page' node type. |
|
||||||
FieldConfig::create([ |
|
||||||
'field_storage' => $field_storage, |
|
||||||
'bundle' => 'page', |
|
||||||
'label' => 'Body', |
|
||||||
'settings' => ['display_summary' => TRUE], |
|
||||||
'required' => TRUE, |
|
||||||
])->save(); |
|
||||||
|
|
||||||
// Assign widget settings for the 'default' form mode. |
|
||||||
EntityFormDisplay::create([ |
|
||||||
'targetEntityType' => 'node', |
|
||||||
'bundle' => 'page', |
|
||||||
'mode' => 'default', |
|
||||||
'status' => TRUE, |
|
||||||
])->setComponent('body', ['type' => 'text_textarea_with_summary']) |
|
||||||
->save(); |
|
||||||
|
|
||||||
$this->account = $this->drupalCreateUser([ |
|
||||||
'administer nodes', |
|
||||||
'create page content', |
|
||||||
'use text format filtered_html', |
|
||||||
]); |
|
||||||
$this->drupalLogin($this->account); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Tests CKEditor plugin functionality for body field. |
|
||||||
*/ |
|
||||||
public function testUi() |
|
||||||
{ |
|
||||||
$session = $this->getSession(); |
|
||||||
$assert_session = $this->assertSession(); |
|
||||||
|
|
||||||
$this->drupalGet("node/add/page"); |
|
||||||
$page = $session->getPage(); |
|
||||||
|
|
||||||
$this->waitForEditor(); |
|
||||||
$this->pressEditorButton('footnotes'); |
|
||||||
$this->assertNotEmpty( |
|
||||||
$assert_session->waitForElementVisible('css', '.cke_1.cke_editor_edit-body-0-value_dialog') |
|
||||||
); |
|
||||||
$assert_session->elementTextContains('css', 'table.cke_dialog .cke_dialog_title', $this->t('Footnotes Dialog')); |
|
||||||
$assert_session->elementTextContains('css', '.cke_dialog_page_contents table tr:first-child', $this->t('Footnote text :')); |
|
||||||
$assert_session->elementTextContains('css', '.cke_dialog_page_contents table tr:last-child', $this->t('Value :')); |
|
||||||
$page->find('css', 'a.cke_dialog_ui_button_cancel')->click(); |
|
||||||
|
|
||||||
$this->assertEmpty($assert_session->elementExists('css', '.cke_1.cke_editor_edit-body-0-value_dialog')->isVisible()); |
|
||||||
|
|
||||||
$texts = ['Text one.', 'Text two.', 'Text tree', 'Text four', 'Text five']; |
|
||||||
foreach ($texts as $key => $value) { |
|
||||||
$this->pressEditorButton('footnotes'); |
|
||||||
$this->assertNotEmpty( |
|
||||||
$assert_session->waitForElementVisible('css', '.cke_1.cke_editor_edit-body-0-value_dialog') |
|
||||||
); |
|
||||||
$assert_session->elementExists('css', '.cke_dialog_page_contents table tr:last-child input')->setValue($key); |
|
||||||
$assert_session->elementExists('css', '.cke_dialog_page_contents table tr:first-child input')->setValue($value); |
|
||||||
$page->find('css', 'a.cke_dialog_ui_button_ok')->click(); |
|
||||||
|
|
||||||
$this->assertEmpty($assert_session->elementExists('css', '.cke_1.cke_editor_edit-body-0-value_dialog')->isVisible()); |
|
||||||
} |
|
||||||
$this->pressEditorButton('source'); |
|
||||||
$body_value = $assert_session->elementExists('css', '.cke .cke_contents .cke_source')->getValue(); |
|
||||||
|
|
||||||
$body_value = str_replace(["\r\n", "\r", "\n"], "", $body_value); |
|
||||||
$body_value = trim($body_value); |
|
||||||
|
|
||||||
$expected_value = '<p>'; |
|
||||||
foreach ($texts as $key => $value) { |
|
||||||
$expected_value .= '<fn value="' . $key . '">' . $value . '</fn>'; |
|
||||||
} |
|
||||||
$expected_value .= '</p>'; |
|
||||||
|
|
||||||
$this->assertEqual($body_value, $expected_value, $this->t('String, formed by CKEditor, is correct.')); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||