30 changed files with 268 additions and 1669 deletions
@ -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,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,9 +0,0 @@ |
|||||||
reference_footnotes: |
|
||||||
ckeditor5: |
|
||||||
plugins: |
|
||||||
- ReferenceFootnotes |
|
||||||
drupal: |
|
||||||
label: 'Reference Footnotes' |
|
||||||
toolbar_items: |
|
||||||
referenceFootnotes: |
|
||||||
label: 'Reference Footnotes' |
|
||||||
@ -1,17 +0,0 @@ |
|||||||
bibcite_footnotes_2_footnote_picker: |
|
||||||
ckeditor5: |
|
||||||
plugins: |
|
||||||
- footnotepicker2.FootnotePicker2 |
|
||||||
|
|
||||||
drupal: |
|
||||||
label: 'Footnote/Citation (Test)' |
|
||||||
library: bibcite_footnotes_2/footnote_picker |
|
||||||
admin_library: bibcite_footnotes_2/footnote_picker |
|
||||||
|
|
||||||
toolbar_items: |
|
||||||
footnotePicker2: |
|
||||||
label: 'Footnoe' |
|
||||||
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> |
|
||||||
@ -1,7 +0,0 @@ |
|||||||
name: 'Bibcite Footnotes CKEditor 5' |
|
||||||
type: module |
|
||||||
description: 'Provides a CKEditor 5 plugin for inserting and editing reference footnotes.' |
|
||||||
package: 'Custom' |
|
||||||
core_version_requirement: '^10.2 || ^11' |
|
||||||
dependencies: |
|
||||||
- drupal:ckeditor5 |
|
||||||
@ -1,19 +0,0 @@ |
|||||||
reference_footnotes: |
|
||||||
js: |
|
||||||
js/ckeditor5/reference-footnotes.js: { type: module } |
|
||||||
css: |
|
||||||
theme: |
|
||||||
css/reference-footnotes.css: {} |
|
||||||
|
|
||||||
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,38 +1,23 @@ |
|||||||
{ |
{ |
||||||
"name": "drupal/footnotes", |
"name": "roblib/bibcite_footnotes", |
||||||
"description": "Add automatically numbered footnotes to your posts.", |
"description": "Inline footnote links for BibCite References with CKEditor 4 and CKEditor 5 support.", |
||||||
"type": "drupal-module", |
"type": "drupal-module", |
||||||
"homepage": "https://drupal.org/project/footnotes", |
"homepage": "https://drupal.org/project/bibcite_footnotes", |
||||||
"authors": [ |
"authors": [ |
||||||
{ |
{ |
||||||
"name": "Andrii Aleksandrov (id.aleks)", |
"name": "Alexander O'Neill (alxp)", |
||||||
"homepage": "https://www.drupal.org/u/idaleks", |
"homepage": "https://www.drupal.org/u/alxp", |
||||||
"role": "Maintainer" |
"role": "Maintainer" |
||||||
|
} |
||||||
|
], |
||||||
|
"support": { |
||||||
|
"issues": "https://drupal.org/project/issues/bibcite_footnotes", |
||||||
|
"source": "https://cgit.drupalcode.org/bibcite_footnotes" |
||||||
}, |
}, |
||||||
{ |
"license": "GPL-2.0+", |
||||||
"name": "Oleksandr Dekhteruk (pifagor)", |
"minimum-stability": "dev", |
||||||
"homepage": "https://www.drupal.org/u/pifagor", |
"require": { |
||||||
"role": "Maintainer" |
"drupal/core": ">=8.6", |
||||||
}, |
"drupal/fakeobjects": "^1.0" |
||||||
{ |
|
||||||
"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,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']; |
|
||||||
} |
|
||||||
|
Before Width: | Height: | Size: 282 B |
@ -1,198 +0,0 @@ |
|||||||
import { Plugin } from 'ckeditor5/src/core'; |
|
||||||
import { ButtonView } from 'ckeditor5/src/ui'; |
|
||||||
import { Widget, toWidget } from 'ckeditor5/src/widget'; |
|
||||||
import icon from './reference-footnotes-icon.svg'; |
|
||||||
|
|
||||||
/** |
|
||||||
* ReferenceFootnotes CKEditor 5 plugin. |
|
||||||
* |
|
||||||
* Provides: |
|
||||||
* - A toolbar button that inserts a <fn> element. |
|
||||||
* - Double-click editing of existing <fn> elements. |
|
||||||
* - Simple browser-prompt based dialog for editing attributes. |
|
||||||
* |
|
||||||
* This keeps the implementation simple and reliable in Drupal's environment. |
|
||||||
* If you later want a full ContextualBalloon-based dialog, this is the place |
|
||||||
* to extend. |
|
||||||
*/ |
|
||||||
export default class ReferenceFootnotes extends Plugin { |
|
||||||
static get requires() { |
|
||||||
return [ Widget ]; |
|
||||||
} |
|
||||||
|
|
||||||
static get pluginName() { |
|
||||||
return 'ReferenceFootnotes'; |
|
||||||
} |
|
||||||
|
|
||||||
init() { |
|
||||||
const editor = this.editor; |
|
||||||
|
|
||||||
// --- SCHEMA -------------------------------------------------
|
|
||||||
// Model element: <fn value="" page="" reference="">text</fn>
|
|
||||||
editor.model.schema.register('fn', { |
|
||||||
allowWhere: '$text', |
|
||||||
allowContentOf: '$text', |
|
||||||
isInline: true, |
|
||||||
isObject: true, |
|
||||||
allowAttributes: [ 'value', 'page', 'reference' ] |
|
||||||
}); |
|
||||||
|
|
||||||
// --- MODEL → VIEW (editing) --------------------------------
|
|
||||||
// Show an inline widget with a class that you can style with an icon.
|
|
||||||
editor.conversion.for('editingDowncast').elementToElement({ |
|
||||||
model: 'fn', |
|
||||||
view: (modelElement, { writer }) => { |
|
||||||
const viewElement = writer.createContainerElement('span', { |
|
||||||
class: 'reference-footnote', |
|
||||||
'data-value': modelElement.getAttribute('value') || '', |
|
||||||
'data-reference': modelElement.getAttribute('reference') || '', |
|
||||||
'data-page': modelElement.getAttribute('page') || '' |
|
||||||
}); |
|
||||||
|
|
||||||
return toWidget(viewElement, writer, { label: editor.t('Reference footnote') }); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
// --- MODEL → VIEW (data/HTML) -------------------------------
|
|
||||||
// Persist as <fn ...>TEXT</fn> in the saved HTML.
|
|
||||||
editor.conversion.for('dataDowncast').elementToElement({ |
|
||||||
model: 'fn', |
|
||||||
view: (modelElement, { writer }) => { |
|
||||||
const attrs = { |
|
||||||
value: modelElement.getAttribute('value') || '', |
|
||||||
reference: modelElement.getAttribute('reference') || '', |
|
||||||
page: modelElement.getAttribute('page') || '' |
|
||||||
}; |
|
||||||
|
|
||||||
const fnElement = writer.createContainerElement('fn', attrs); |
|
||||||
|
|
||||||
// Put inner text into the <fn> element.
|
|
||||||
const firstChild = modelElement.getChild(0); |
|
||||||
const textData = firstChild && firstChild.is( 'text' ) ? firstChild.data : ''; |
|
||||||
if (textData) { |
|
||||||
const textNode = writer.createText(textData); |
|
||||||
writer.insert(textNode, fnElement, 0); |
|
||||||
} |
|
||||||
|
|
||||||
return fnElement; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
// --- VIEW → MODEL (upcast) ---------------------------------
|
|
||||||
// Convert <fn> tags back into model elements.
|
|
||||||
editor.conversion.for('upcast').elementToElement({ |
|
||||||
view: { |
|
||||||
name: 'fn' |
|
||||||
}, |
|
||||||
model: (viewElement, { writer }) => { |
|
||||||
return writer.createElement('fn', { |
|
||||||
value: viewElement.getAttribute('value') || '', |
|
||||||
reference: viewElement.getAttribute('reference') || '', |
|
||||||
page: viewElement.getAttribute('page') || '' |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
// --- TOOLBAR BUTTON -----------------------------------------
|
|
||||||
editor.ui.componentFactory.add('referenceFootnotes', locale => { |
|
||||||
const view = new ButtonView(locale); |
|
||||||
|
|
||||||
view.set({ |
|
||||||
label: editor.t('Add reference footnote'), |
|
||||||
icon, |
|
||||||
tooltip: true |
|
||||||
}); |
|
||||||
|
|
||||||
view.on('execute', () => { |
|
||||||
this.openFootnoteDialog(null); |
|
||||||
}); |
|
||||||
|
|
||||||
return view; |
|
||||||
}); |
|
||||||
|
|
||||||
// --- DOUBLE CLICK HANDLER -----------------------------------
|
|
||||||
editor.editing.view.document.on('dblclick', (evt, data) => { |
|
||||||
const viewElement = data.target; |
|
||||||
const modelElement = editor.editing.mapper.toModelElement(viewElement); |
|
||||||
|
|
||||||
if (modelElement && modelElement.name === 'fn') { |
|
||||||
this.openFootnoteDialog(modelElement); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Opens a simple "dialog" (browser prompts) to create or edit a footnote. |
|
||||||
* |
|
||||||
* @param {?module:engine/model/element~Element} existingFn |
|
||||||
* The existing <fn> model element, or null for a new one. |
|
||||||
*/ |
|
||||||
openFootnoteDialog(existingFn) { |
|
||||||
const editor = this.editor; |
|
||||||
|
|
||||||
// --- Read existing values (if editing) ----------------------
|
|
||||||
let currentText = ''; |
|
||||||
let currentValue = ''; |
|
||||||
let currentReference = ''; |
|
||||||
let currentPage = ''; |
|
||||||
|
|
||||||
if (existingFn) { |
|
||||||
const firstChild = existingFn.getChild(0); |
|
||||||
currentText = firstChild && firstChild.is('text') ? firstChild.data : ''; |
|
||||||
|
|
||||||
currentValue = existingFn.getAttribute('value') || ''; |
|
||||||
currentReference = existingFn.getAttribute('reference') || ''; |
|
||||||
currentPage = existingFn.getAttribute('page') || ''; |
|
||||||
} |
|
||||||
|
|
||||||
// --- Simple prompts for now --------------------------------
|
|
||||||
const text = window.prompt(editor.t('Footnote text:'), currentText || ''); |
|
||||||
if (text === null) { |
|
||||||
return; // user cancelled
|
|
||||||
} |
|
||||||
|
|
||||||
const value = window.prompt(editor.t('Footnote value (e.g. 1, 2, 3):'), currentValue || ''); |
|
||||||
if (value === null) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
const reference = window.prompt(editor.t('Reference (optional):'), currentReference || ''); |
|
||||||
if (reference === null) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
const page = window.prompt(editor.t('Page (optional):'), currentPage || ''); |
|
||||||
if (page === null) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
// --- Write changes to the model -----------------------------
|
|
||||||
editor.model.change(writer => { |
|
||||||
if (!existingFn) { |
|
||||||
// Insert a brand new <fn> element at the selection.
|
|
||||||
const fnElement = writer.createElement('fn', { |
|
||||||
value: value, |
|
||||||
reference: reference, |
|
||||||
page: page |
|
||||||
}); |
|
||||||
|
|
||||||
// Insert the element and then its visible text.
|
|
||||||
editor.model.insertObject(fnElement, editor.model.document.selection); |
|
||||||
writer.insertText(text, fnElement, 0); |
|
||||||
} |
|
||||||
else { |
|
||||||
// Update attributes.
|
|
||||||
writer.setAttribute('value', value, existingFn); |
|
||||||
writer.setAttribute('reference', reference, existingFn); |
|
||||||
writer.setAttribute('page', page, existingFn); |
|
||||||
|
|
||||||
// Replace inner text.
|
|
||||||
const children = Array.from(existingFn.getChildren()); |
|
||||||
for (const child of children) { |
|
||||||
writer.remove(child); |
|
||||||
} |
|
||||||
writer.insertText(text, existingFn, 0); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,19 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
namespace Drupal\bibcite_footnotes_2\Plugin\CKEditor5Plugin; |
|
||||||
|
|
||||||
use Drupal\ckeditor5\Plugin\CKEditor5PluginDefault; |
|
||||||
use Drupal\Core\StringTranslation\TranslatableMarkup; |
|
||||||
|
|
||||||
#[CKEditor5Plugin( |
|
||||||
id: 'reference_footnotes', |
|
||||||
label: new TranslatableMarkup('Reference Footnotes'), |
|
||||||
ckeditor5: 'reference_footnotes', |
|
||||||
library: 'bibcite_footnotes_2/reference_footnotes', |
|
||||||
elements: [ |
|
||||||
'<fn value page reference>', |
|
||||||
], |
|
||||||
)] |
|
||||||
class ReferenceFootnotes extends CKEditor5PluginDefault { |
|
||||||
|
|
||||||
} |
|
||||||
@ -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,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.')); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
Loading…
Reference in new issue