On 04/15/2011 12:54 PM, Rob Oakes wrote:
Hi Richard,
Thanks for all of the advice that you've given me already. Using your
suggestions, I've been able to get a skeleton in place that lets me start to
play with different ways of exporting the footnotes as end notes. Those
changes are attached as a patch.
Good start!
While everything works pretty well for the InsetFoot (meaning that it only
prints the label rather than the whole inset), I haven't yet started playing
around with the output in InsetPrintEndnotes. This is mostly because I'm
terribly clueless. I had a couple of quick (I hope) questions:
1.) What methods do I need to implement so that the inset is able to work in
XHTML documents? I've started with the xhtml method, but stopped because I
wasn't sure what others were necessary.
For XHTML, you need the xhtml() method and, probably, validate(), to
write the needed CSS, the way it's done in InsetToc::validate(). I guess
there's a question what, if anything, the inset should do for
LaTeX---possibly, issue \theendnotes and invoke something equivalent to
what we have in foottoend.module---but we can address that later. Most
of the rest should be fine as inherited from InsetCommand. Here again,
I'd suggest you look at InsetPrintIndex. Since this new inset has no
parameters, and doesn't respond to requests to modify itself, you don't
need doDispatch() or getStatus(). You do need findInfo(),
defaultCommand(), and isCompatibleCommand(), but these will all be
pretty trivial in this case, again since there's only one command
(theendnotes, I guess) and there are no parameters. (See InsetCommand.h
for what these do.)
You also need to give the new inset a code in InsetCode.h and then add
it to the "translator" at the top of Inset.cpp. And there will need to
be code in createInsetHelper(), in factory.cpp, to make such insets when
they are requested (during reading a LyX file, e.g.). If you grep for
INDEX_PRINT_CODE, you'll see all the places it is mentioned and that
will serve as a guide.
2.) What do I need to add to lib> layouts? Should I create a module that
allows XHTML endnotes? Or once I've got all of the appropriate methods
implemented, will the new inset simply show up in the UI?
Once you have the inset, you'll want to add something to
lib/ui/stdmenus.ui. That will be enough. There is no support in modules,
currently, for "command" type insets. I hope to do that in the 2.1
cycle, but these would not support the sort of complex operation we're
talking about.
Comments on the code so far below.
=== modified file 'src/BufferParams.cpp'
--- src/BufferParams.cpp 2011-03-25 14:27:13 +0000
+++ src/BufferParams.cpp 2011-04-14 03:34:28 +0000
@@ -415,6 +415,7 @@
html_math_output = MathML;
html_math_img_scale = 1.0;
html_css_as_file = false;
+ html_footnotes_as_endnotes = false;
You know, we may not even need this. If the new inset is there, then we
want to do this, right? If not, not. So InsetPrintEndnotes::validate()
could set a flag in the LaTeXFeatures object that told us to do this.
output_sync = false;
use_refstyle = true;
@@ -853,6 +854,8 @@
lex>> html_be_strict;
} else if (token == "\\html_css_as_file") {
lex>> html_css_as_file;
+ } else if (token == "\\html_footnotes_as_endnotes") {
+ lex>> html_footnotes_as_endnotes;
} else if (token == "\\html_math_img_scale") {
lex>> html_math_img_scale;
} else if (token == "\\html_latex_start") {
@@ -1094,6 +1097,7 @@
<< "\\output_changes "<< convert<string>(outputChanges)<< '\n'
<< "\\html_math_output "<< html_math_output<< '\n'
<< "\\html_css_as_file "<< html_css_as_file<< '\n'
+ << "\\html_footnotes_as_endnotes "<< html_footnotes_as_endnotes<<
'\n'
<< "\\html_be_strict "<< convert<string>(html_be_strict)<< '\n';
if (html_math_img_scale != 1.0)
=== modified file 'src/BufferParams.h'
--- src/BufferParams.h 2011-02-15 18:28:23 +0000
+++ src/BufferParams.h 2011-04-14 03:19:40 +0000
@@ -405,8 +405,10 @@
std::string html_latex_start;
///
std::string html_latex_end;
- ///
+ /// Write Document CSS as a Separate File
bool html_css_as_file;
+ /// write all footnotes as endnotes with back link
+ bool html_footnotes_as_endnotes;
/// generate output usable for reverse/forward search
bool output_sync;
/// custom LaTeX macro from user instead our own
=== modified file 'src/insets/InsetFoot.cpp'
--- src/insets/InsetFoot.cpp 2011-03-16 06:44:29 +0000
+++ src/insets/InsetFoot.cpp 2011-04-15 16:21:50 +0000
@@ -15,6 +15,9 @@
#include "Buffer.h"
#include "BufferParams.h"
+#include "BufferView.h"
+#include "Cursor.h"
+
#include "Counters.h"
#include "Language.h"
#include "Layout.h"
@@ -23,14 +26,25 @@
#include "TextClass.h"
#include "TocBackend.h"
+#include "output_xhtml.h"
+
#include "support/debug.h"
#include "support/docstream.h"
#include "support/gettext.h"
+#include<ostream>
+#include<algorithm>
+
using namespace std;
namespace lyx {
+/////////////////////////////////////////////////////////////////////
+//
+// InsetFoot
+//
+///////////////////////////////////////////////////////////////////////
+
InsetFoot::InsetFoot(Buffer * buf)
: InsetFootlike(buf)
{}
@@ -116,6 +130,18 @@
return PLAINTEXT_NEWLINE + 1; // one char on a separate line
}
+docstring InsetFoot::xhtml(XHTMLStream& xs, OutputParams const& runparams)
const
+{
+ if (buffer().masterBuffer()->params().html_footnotes_as_endnotes ==
true) {
You don't need to test "== true". If it's true, it's true.
+ string const magic = paragraphs().front().magicLabel();
+ string const attr = "href='#" + magic + "' class='endnote'";
+ xs<< html::CompTag("a", attr);
+ return insetAsXHTML(xs, runparams, WriteLabel);
I think this is probably wrong for what you want. This will write the
contents of the footnote at this point as well. The Write* stuff limits
what besides the contents is written. I think maybe you can just return
docstring() here.
+ }
+
+ return insetAsXHTML(xs, runparams, WriteEverything);
Here, it is better to do:
return InsetFootlike::xhtml(xs, runparams);
and pass it up the inheritance chain rather than to copy and paste from
the parent.
+}
+
Finally, we can invert the logic here, so as to do the simple thing
first and get it out of the way. So:
+docstring InsetFoot::xhtml(XHTMLStream& xs, OutputParams const& runparams)
const
+{
+ if (!buffer().masterBuffer()->params().html_footnotes_as_endnotes)
+ return InsetFootlike::xhtml(xs, runparams);
+ string const magic = paragraphs().front().magicLabel();
+ string const attr = "href='#" + magic + "' class='endnote'";
+ xs<< html::CompTag("a", attr);
+ return docstring();
+}
+
int InsetFoot::docbook(odocstream& os, OutputParams const& runparams) const
{
@@ -126,4 +152,66 @@
return i;
}
+namespace {
+
+struct FootnoteEntry
+{
+ FootnoteEntry() {}
+
+ FootnoteEntry(docstring const& s, DocIterator const& d)
+ : dit(d)
+ {}
+ docstring foottext;
+ DocIterator dit;
+};
+} // anonymous namespace
+
+/////////////////////////////////////////////////////////////////////
+//
+// InsetPrintEndnotes
+//
+///////////////////////////////////////////////////////////////////////
+
+InsetPrintEndnotes::InsetPrintEndnotes(Buffer *buf, const InsetCommandParams&
p)
+ : InsetCommand(buf, p)
+{}
+
+docstring InsetPrintEndnotes::xhtml(XHTMLStream&, const OutputParams& op)
const
+{
+ BufferParams const& bp = buffer().masterBuffer()->params();
+
+ Toc const& toc = buffer().tocBackend().toc("footnotes");
+ if (toc.empty())
+ return docstring();
+
+ // Collect the Footnotes in Useable Form
+ Toc::const_iterator it = toc.begin();
+ Toc::const_iterator const en = toc.end();
+ vector<FootnoteEntry> entries;
+ for (; it !=en; ++it)
+ entries.push_back(FootnoteEntry(it->str(), it->dit()));
+
+ Layout const& lay = bp.documentClass().htmlTOCLayout();
+ string const& tocclass = lay.defaultCSSClass();
+ string const tocattr = "class'tochead " + tocclass + "'";
+
Probably you will want some other sort of CSS here. Maybe there is some
way explicitly to treat "Footnote List" as as section or chapter title,
as the case may be.
+ odocstringstream ods;
+ XHTMLStream xs(ods);
+
+ xs<< html::StartTag("div", "class='footnotelist'");
+ xs<< html::StartTag(lay.htmltag(), lay.htmlattr())
+ << _("FootnoteList")
Notes? Endnotes?
+ << html::EndTag(lay.htmltag());
+ Font const dummy;
+
+ vector<FootnoteEntry>::const_iterator eit = entries.begin();
+ vector<FootnoteEntry>::const_iterator const een = entries.end();
+ int cur_entry_numbr = -1;
+ int prev_entry_numbr = -1;
+ for (; eit!=een; ++eit) {
+ Paragraph const& par = eit->dit.innerParagraph();
+ // Print XHTML Footnotes with backlink to location in text
+ }
+}
+
} // namespace lyx
=== modified file 'src/insets/InsetFoot.h'
--- src/insets/InsetFoot.h 2011-03-29 18:10:40 +0000
+++ src/insets/InsetFoot.h 2011-04-14 22:11:21 +0000
@@ -14,6 +14,7 @@
#define INSETFOOT_H
#include "InsetFootlike.h"
+#include "InsetCommand.h"
namespace lyx {
@@ -26,6 +27,9 @@
public:
///
InsetFoot(Buffer *);
+ ///
+ docstring xhtml(XHTMLStream&, const OutputParams&) const;
+
private:
///
InsetCode lyxCode() const { return FOOT_CODE; }
@@ -49,6 +53,16 @@
docstring custom_label_;
};
+class InsetPrintEndnotes : public InsetCommand {
+public:
+ ///
+ InsetPrintEndnotes(Buffer * buf, InsetCommandParams const&);
+ ///@{
+ ///
+ docstring xhtml(XHTMLStream&, OutputParams const&) const;
+ ///
+ //@}
+};
} // namespace lyx
Generally, the approach looks right to me.
Richard