mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-25 19:07:45 +00:00
Author-year citations for XHTML output.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@32969 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
374b5ebd72
commit
782db81f77
@ -204,7 +204,8 @@ docstring convertLaTeXCommands(docstring const & str)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type)
|
||||
: is_bibtex_(true), bib_key_(key), entry_type_(type), info_()
|
||||
: is_bibtex_(true), bib_key_(key), entry_type_(type), info_(),
|
||||
modifier_(0)
|
||||
{}
|
||||
|
||||
|
||||
@ -423,15 +424,24 @@ docstring const BiblioInfo::getAbbreviatedAuthor(docstring const & key) const
|
||||
}
|
||||
|
||||
|
||||
docstring const BiblioInfo::getYear(docstring const & key) const
|
||||
docstring const BiblioInfo::getCiteNumber(docstring const & key) const
|
||||
{
|
||||
BiblioInfo::const_iterator it = find(key);
|
||||
if (it == end())
|
||||
return docstring();
|
||||
BibTeXInfo const & data = it->second;
|
||||
return data.citeNumber();
|
||||
}
|
||||
|
||||
|
||||
docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) const
|
||||
{
|
||||
BiblioInfo::const_iterator it = find(key);
|
||||
if (it == end())
|
||||
return docstring();
|
||||
BibTeXInfo const & data = it->second;
|
||||
docstring year = data.getYear();
|
||||
if (!year.empty())
|
||||
return year;
|
||||
if (year.empty()) {
|
||||
// let's try the crossref
|
||||
docstring const xref = data.getXRef();
|
||||
if (xref.empty())
|
||||
@ -440,8 +450,11 @@ docstring const BiblioInfo::getYear(docstring const & key) const
|
||||
if (xrefit == end())
|
||||
return _("No year"); // no luck again
|
||||
BibTeXInfo const & xref_data = xrefit->second;
|
||||
return xref_data.getYear();
|
||||
return data.getYear();
|
||||
year = xref_data.getYear();
|
||||
}
|
||||
if (use_modifier && data.modifier() != 0)
|
||||
year += data.modifier();
|
||||
return year;
|
||||
}
|
||||
|
||||
|
||||
@ -604,7 +617,15 @@ namespace {
|
||||
// used in xhtml to sort a list of BibTeXInfo objects
|
||||
bool lSorter(BibTeXInfo const * lhs, BibTeXInfo const * rhs)
|
||||
{
|
||||
return lhs->getAbbreviatedAuthor() < rhs->getAbbreviatedAuthor();
|
||||
docstring const lauth = lhs->getAbbreviatedAuthor();
|
||||
docstring const rauth = rhs->getAbbreviatedAuthor();
|
||||
docstring const lyear = lhs->getYear();
|
||||
docstring const ryear = rhs->getYear();
|
||||
docstring const ltitl = lhs->operator[]("title");
|
||||
docstring const rtitl = rhs->operator[]("title");
|
||||
return (lauth < rauth)
|
||||
|| (lauth == rauth && lyear < ryear)
|
||||
|| (lauth == rauth && lyear == ryear && ltitl < rtitl);
|
||||
}
|
||||
}
|
||||
|
||||
@ -655,19 +676,50 @@ void BiblioInfo::collectCitedEntries(Buffer const & buf)
|
||||
void BiblioInfo::makeCitationLabels(Buffer const & buf)
|
||||
{
|
||||
collectCitedEntries(buf);
|
||||
// FIXME It'd be nice to do author-year as well as numerical
|
||||
// and maybe even some other sorts of labels.
|
||||
CiteEngine const engine = buf.params().citeEngine();
|
||||
bool const numbers =
|
||||
(engine == ENGINE_BASIC || engine == ENGINE_NATBIB_NUMERICAL);
|
||||
|
||||
int keynumber = 0;
|
||||
char modifier = 0;
|
||||
// used to remember the last one we saw
|
||||
// we'll be comparing entries to see if we need to add
|
||||
// modifiers, like "1984a"
|
||||
map<docstring, BibTeXInfo>::iterator last;
|
||||
|
||||
vector<docstring>::const_iterator it = cited_entries_.begin();
|
||||
vector<docstring>::const_iterator const en = cited_entries_.end();
|
||||
int keynumber = 0;
|
||||
for (; it != en; ++it) {
|
||||
map<docstring, BibTeXInfo>::iterator const biit = bimap_.find(*it);
|
||||
// this shouldn't happen, but...
|
||||
if (biit == bimap_.end())
|
||||
// ...fail gracefully, anyway.
|
||||
continue;
|
||||
BibTeXInfo & entry = biit->second;
|
||||
docstring const key = convert<docstring>(++keynumber);
|
||||
entry.setCiteKey(key);
|
||||
if (numbers) {
|
||||
docstring const num = convert<docstring>(++keynumber);
|
||||
entry.setCiteNumber(num);
|
||||
} else {
|
||||
if (it != cited_entries_.begin()
|
||||
&& entry.getAbbreviatedAuthor() == last->second.getAbbreviatedAuthor()
|
||||
// we access the year via getYear() so as to get it from the xref,
|
||||
// if we need to do so
|
||||
&& getYear(entry.key()) == getYear(last->second.key())) {
|
||||
if (modifier == 0) {
|
||||
// so the last one should have been 'a'
|
||||
last->second.setModifier('a');
|
||||
modifier = 'b';
|
||||
} else if (modifier == 'z')
|
||||
modifier = 'A';
|
||||
else
|
||||
modifier++;
|
||||
} else {
|
||||
modifier = 0;
|
||||
}
|
||||
entry.setModifier(modifier);
|
||||
// remember the last one
|
||||
last = biit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,10 +86,16 @@ public:
|
||||
docstring const & label() const { return label_; }
|
||||
///
|
||||
docstring const & key() const { return bib_key_; }
|
||||
/// numerical key for citing this entry. currently used only
|
||||
/// by XHTML output routines.
|
||||
docstring citeNumber() const { return cite_number_; }
|
||||
///
|
||||
docstring citeKey() const { return cite_key_; }
|
||||
void setCiteNumber(docstring const & num) { cite_number_ = num; }
|
||||
/// a,b,c, etc, for author-year. currently used only by XHTML
|
||||
/// output routines.
|
||||
char modifier() const { return modifier_; }
|
||||
///
|
||||
void setCiteKey(docstring const & k) { cite_key_ = k; }
|
||||
void setModifier(char c) { modifier_ = c; }
|
||||
///
|
||||
docstring entryType() const { return entry_type_; }
|
||||
///
|
||||
@ -114,9 +120,10 @@ private:
|
||||
docstring entry_type_;
|
||||
/// a cache for getInfo()
|
||||
mutable docstring info_;
|
||||
/// key to use when citing this entry
|
||||
/// currently used only by XHTML output routines
|
||||
docstring cite_key_;
|
||||
///
|
||||
docstring cite_number_;
|
||||
///
|
||||
char modifier_;
|
||||
/// our map: <field, value>
|
||||
std::map <docstring, docstring> bimap_;
|
||||
};
|
||||
@ -136,10 +143,15 @@ public:
|
||||
std::vector<docstring> const getEntries() const;
|
||||
/// \return the short form of an authorlist
|
||||
docstring const getAbbreviatedAuthor(docstring const & key) const;
|
||||
/// \return the year from the bibtex data record
|
||||
/// \return the year from the bibtex data record for \param key
|
||||
/// if \param use_modifier is true, then we will also append any
|
||||
/// modifier for this entry (e.g., 1998b).
|
||||
/// Note that this will get the year from the crossref if it's
|
||||
/// not present in the record itself
|
||||
docstring const getYear(docstring const & key) const;
|
||||
/// not present in the record itself.
|
||||
docstring const getYear(docstring const & key,
|
||||
bool use_modifier = false) const;
|
||||
///
|
||||
docstring const getCiteNumber(docstring const & key) const;
|
||||
/// \return formatted BibTeX data associated with a given key.
|
||||
/// Empty if no info exists.
|
||||
/// Note that this will retrieve data from the crossref as needed.
|
||||
@ -177,7 +189,10 @@ public:
|
||||
void collectCitedEntries(Buffer const & buf);
|
||||
/// A list of BibTeX keys cited in the current document, sorted by
|
||||
/// the last name of the author.
|
||||
std::vector<docstring> const & citedEntries() const { return cited_entries_; }
|
||||
/// Make sure you have called collectCitedEntries() before you try to
|
||||
/// use this. You should probably call it just before you use this.
|
||||
std::vector<docstring> const & citedEntries() const
|
||||
{ return cited_entries_; }
|
||||
///
|
||||
void makeCitationLabels(Buffer const & buf);
|
||||
///
|
||||
|
@ -909,10 +909,17 @@ void InsetBibtex::validate(LaTeXFeatures & features) const
|
||||
}
|
||||
|
||||
|
||||
// FIXME
|
||||
// docstring InsetBibtex::entriesAsXHTML(vector<docstring> const & entries)
|
||||
// And then here just: entriesAsXHTML(buffer().masterBibInfo().citedEntries())
|
||||
docstring InsetBibtex::xhtml(XHTMLStream & xs, OutputParams const &) const
|
||||
{
|
||||
BiblioInfo const & bibinfo = buffer().masterBibInfo();
|
||||
vector<docstring> const & cites = bibinfo.citedEntries();
|
||||
CiteEngine const engine = buffer().params().citeEngine();
|
||||
bool const numbers =
|
||||
(engine == ENGINE_BASIC || engine == ENGINE_NATBIB_NUMERICAL);
|
||||
|
||||
xs << StartTag("h2", "class='bibtex'")
|
||||
<< _("References")
|
||||
<< EndTag("h2")
|
||||
@ -931,7 +938,17 @@ docstring InsetBibtex::xhtml(XHTMLStream & xs, OutputParams const &) const
|
||||
// The same name/id problem we have elsewhere.
|
||||
string const attr = "id='" + to_utf8(entry.key()) + "'";
|
||||
xs << CompTag("a", attr);
|
||||
docstring citekey = entry.citeKey();
|
||||
docstring citekey;
|
||||
if (numbers)
|
||||
citekey = entry.citeNumber();
|
||||
else {
|
||||
docstring const auth = entry.getAbbreviatedAuthor();
|
||||
// we do it this way so as to access the xref, if necessary
|
||||
// note that this also gives us the modifier
|
||||
docstring const year = bibinfo.getYear(*vit, true);
|
||||
if (!auth.empty() && !year.empty())
|
||||
citekey = auth + ' ' + year;
|
||||
}
|
||||
if (citekey.empty()) {
|
||||
citekey = entry.label();
|
||||
if (citekey.empty())
|
||||
@ -947,6 +964,7 @@ docstring InsetBibtex::xhtml(XHTMLStream & xs, OutputParams const &) const
|
||||
<< bibinfo.getInfo(entry.key())
|
||||
<< EndTag("span")
|
||||
<< EndTag("div");
|
||||
xs.cr();
|
||||
}
|
||||
xs << EndTag("div");
|
||||
return docstring();
|
||||
|
@ -199,22 +199,33 @@ string asValidLatexCommand(string const & input, CiteEngine const engine)
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
inline docstring wrapCitation(docstring const & key,
|
||||
docstring const & content, bool for_xhtml)
|
||||
{
|
||||
if (!for_xhtml)
|
||||
return content;
|
||||
// we have to do the escaping here, because we will ultimately
|
||||
// write this as a raw string, so as not to escape the tags.
|
||||
return "<a href='#" + key + "'>" + html::htmlize(content) + "</a>";
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
docstring InsetCitation::generateLabel() const
|
||||
docstring InsetCitation::generateLabel(bool for_xhtml) const
|
||||
{
|
||||
docstring label;
|
||||
label = complexLabel();
|
||||
label = complexLabel(for_xhtml);
|
||||
|
||||
// Fallback to fail-safe
|
||||
if (label.empty())
|
||||
label = basicLabel();
|
||||
label = basicLabel(for_xhtml);
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
docstring InsetCitation::complexLabel() const
|
||||
docstring InsetCitation::complexLabel(bool for_xhtml) const
|
||||
{
|
||||
Buffer const & buf = buffer();
|
||||
// Only start the process off after the buffer is loaded from file.
|
||||
@ -300,83 +311,90 @@ docstring InsetCitation::complexLabel() const
|
||||
for (; it != end; ++it) {
|
||||
// get the bibdata corresponding to the key
|
||||
docstring const author = biblist.getAbbreviatedAuthor(*it);
|
||||
docstring const year = biblist.getYear(*it);
|
||||
docstring const year = biblist.getYear(*it, for_xhtml);
|
||||
docstring const citenum = for_xhtml ? biblist.getCiteNumber(*it) : *it;
|
||||
|
||||
// Something isn't right. Fail safely.
|
||||
if (author.empty() || year.empty())
|
||||
// We can't construct a "complex" label without that info.
|
||||
// So fail safely.
|
||||
return docstring();
|
||||
|
||||
// authors1/<before>; ... ;
|
||||
// authors_last, <after>
|
||||
if (cite_type == "cite") {
|
||||
if (engine == ENGINE_BASIC) {
|
||||
label += *it + sep_str;
|
||||
label += wrapCitation(*it, citenum, for_xhtml) + sep_str;
|
||||
} else if (engine == ENGINE_JURABIB) {
|
||||
if (it == keys.begin())
|
||||
label += author + before_str + sep_str;
|
||||
label += wrapCitation(*it, author, for_xhtml) + before_str + sep_str;
|
||||
else
|
||||
label += author + sep_str;
|
||||
label += wrapCitation(*it, author, for_xhtml) + sep_str;
|
||||
}
|
||||
}
|
||||
|
||||
// nocite
|
||||
} else if (cite_type == "nocite") {
|
||||
else if (cite_type == "nocite") {
|
||||
label += *it + sep_str;
|
||||
|
||||
}
|
||||
// (authors1 (<before> year); ... ;
|
||||
// authors_last (<before> year, <after>)
|
||||
} else if (cite_type == "citet") {
|
||||
else if (cite_type == "citet") {
|
||||
switch (engine) {
|
||||
case ENGINE_NATBIB_AUTHORYEAR:
|
||||
label += author + op_str + before_str +
|
||||
year + cp + sep_str;
|
||||
wrapCitation(*it, year, for_xhtml) + cp + sep_str;
|
||||
break;
|
||||
case ENGINE_NATBIB_NUMERICAL:
|
||||
label += author + op_str + before_str + '#' + *it + cp + sep_str;
|
||||
label += author + op_str + before_str +
|
||||
wrapCitation(*it, citenum, for_xhtml) + cp + sep_str;
|
||||
break;
|
||||
case ENGINE_JURABIB:
|
||||
label += before_str + author + op_str +
|
||||
year + cp + sep_str;
|
||||
wrapCitation(*it, year, for_xhtml) + cp + sep_str;
|
||||
break;
|
||||
case ENGINE_BASIC:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
// author, year; author, year; ...
|
||||
} else if (cite_type == "citep" ||
|
||||
else if (cite_type == "citep" ||
|
||||
cite_type == "citealp") {
|
||||
if (engine == ENGINE_NATBIB_NUMERICAL) {
|
||||
label += *it + sep_str;
|
||||
label += wrapCitation(*it, citenum, for_xhtml) + sep_str;
|
||||
} else {
|
||||
label += author + ", " + year + sep_str;
|
||||
label += wrapCitation(*it, author + ", " + year, for_xhtml) + sep_str;
|
||||
}
|
||||
|
||||
}
|
||||
// (authors1 <before> year;
|
||||
// authors_last <before> year, <after>)
|
||||
} else if (cite_type == "citealt") {
|
||||
else if (cite_type == "citealt") {
|
||||
switch (engine) {
|
||||
case ENGINE_NATBIB_AUTHORYEAR:
|
||||
label += author + ' ' + before_str +
|
||||
year + sep_str;
|
||||
wrapCitation(*it, year, for_xhtml) + sep_str;
|
||||
break;
|
||||
case ENGINE_NATBIB_NUMERICAL:
|
||||
label += author + ' ' + before_str + '#' + *it + sep_str;
|
||||
label += author + ' ' + before_str + '#' +
|
||||
wrapCitation(*it, citenum, for_xhtml) + sep_str;
|
||||
break;
|
||||
case ENGINE_JURABIB:
|
||||
label += before_str + author + ' ' +
|
||||
year + sep_str;
|
||||
label += before_str +
|
||||
wrapCitation(*it, author + ' ' + year, for_xhtml) + sep_str;
|
||||
break;
|
||||
case ENGINE_BASIC:
|
||||
break;
|
||||
}
|
||||
|
||||
// author; author; ...
|
||||
} else if (cite_type == "citeauthor") {
|
||||
label += author + sep_str;
|
||||
|
||||
}
|
||||
// author; author; ...
|
||||
else if (cite_type == "citeauthor") {
|
||||
label += wrapCitation(*it, author, for_xhtml) + sep_str;
|
||||
}
|
||||
// year; year; ...
|
||||
} else if (cite_type == "citeyear" ||
|
||||
else if (cite_type == "citeyear" ||
|
||||
cite_type == "citeyearpar") {
|
||||
label += year + sep_str;
|
||||
label += wrapCitation(*it, year, for_xhtml) + sep_str;
|
||||
}
|
||||
}
|
||||
label = rtrim(rtrim(label), sep);
|
||||
@ -409,7 +427,7 @@ docstring InsetCitation::complexLabel() const
|
||||
}
|
||||
|
||||
|
||||
docstring InsetCitation::basicLabel() const
|
||||
docstring InsetCitation::basicLabel(bool for_xhtml) const
|
||||
{
|
||||
docstring keys = getParam("key");
|
||||
docstring label;
|
||||
@ -420,10 +438,10 @@ docstring InsetCitation::basicLabel() const
|
||||
while (contains(keys, ',')) {
|
||||
docstring key;
|
||||
keys = ltrim(split(keys, key, ','));
|
||||
label += ", " + key;
|
||||
label += ", " + wrapCitation(key, key, for_xhtml);
|
||||
}
|
||||
} else {
|
||||
label = keys;
|
||||
label = wrapCitation(keys, keys, for_xhtml);
|
||||
}
|
||||
|
||||
docstring const & after = getParam("after");
|
||||
@ -510,46 +528,9 @@ docstring InsetCitation::xhtml(XHTMLStream & xs, OutputParams const &) const
|
||||
if (cmd == "nocite")
|
||||
return docstring();
|
||||
|
||||
BiblioInfo const & bi = buffer().masterBibInfo();
|
||||
docstring const & key_list = getParam("key");
|
||||
if (key_list.empty())
|
||||
return docstring();
|
||||
// have to output this raw, because generateLabel() will include tags
|
||||
xs << XHTMLStream::NextRaw() << generateLabel(true);
|
||||
|
||||
// FIXME We should do a better job outputing different things for the
|
||||
// different citation styles. For now, we use square brackets for every
|
||||
// case.
|
||||
xs << "[";
|
||||
docstring const & before = getParam("before");
|
||||
if (!before.empty())
|
||||
xs << before << " ";
|
||||
|
||||
vector<docstring> const keys = getVectorFromString(key_list);
|
||||
vector<docstring>::const_iterator it = keys.begin();
|
||||
vector<docstring>::const_iterator const en = keys.end();
|
||||
bool first = true;
|
||||
for (; it != en; ++it) {
|
||||
BiblioInfo::const_iterator const bt = bi.find(*it);
|
||||
if (bt == bi.end())
|
||||
continue;
|
||||
BibTeXInfo const & bibinfo = bt->second;
|
||||
if (!first) {
|
||||
xs << ", ";
|
||||
first = false;
|
||||
}
|
||||
docstring citekey = bibinfo.citeKey();
|
||||
if (citekey.empty()) {
|
||||
citekey = bibinfo.label();
|
||||
if (citekey.empty())
|
||||
citekey = *it;
|
||||
}
|
||||
string const attr = "href='#" + to_utf8(*it) + "'";
|
||||
xs << StartTag("a", attr) << citekey << EndTag("a");
|
||||
}
|
||||
|
||||
docstring const & after = getParam("after");
|
||||
if (!after.empty())
|
||||
xs << ", " << after;
|
||||
xs << "]";
|
||||
return docstring();
|
||||
}
|
||||
|
||||
|
@ -74,12 +74,12 @@ public:
|
||||
private:
|
||||
///
|
||||
Inset * clone() const { return new InsetCitation(*this); }
|
||||
/// This function does the donkey work of creating the pretty label
|
||||
docstring generateLabel() const;
|
||||
///
|
||||
docstring complexLabel() const;
|
||||
///
|
||||
docstring basicLabel() const;
|
||||
/// tries to make a pretty label and makes a basic one if not
|
||||
docstring generateLabel(bool for_xhtml = false) const;
|
||||
/// makes a pretty label
|
||||
docstring complexLabel(bool for_xhtml = false) const;
|
||||
/// makes a very basic label, in case we can't make a pretty one
|
||||
docstring basicLabel(bool for_xhtml = false) const;
|
||||
/// we'll eventually want to be able to get info on this from the
|
||||
/// various CiteEngines
|
||||
static ParamInfo param_info_;
|
||||
|
Loading…
Reference in New Issue
Block a user