X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Foutput_xhtml.cpp;h=fdf8681b56b8964946bbf3da2b89bbb8f2b3d412;hb=2098f1d8c20d51e63e670bcdc9da8996068975bf;hp=1232e79a841451345207b27726b6ff8dc0ea93f7;hpb=6967440797893231c18a740a233a912292879f49;p=lyx.git diff --git a/src/output_xhtml.cpp b/src/output_xhtml.cpp index 1232e79a84..fdf8681b56 100644 --- a/src/output_xhtml.cpp +++ b/src/output_xhtml.cpp @@ -75,6 +75,66 @@ docstring htmlize(docstring const & str) { } +string escapeChar(char c) +{ + string str; + switch (c) { + case ' ': + str += " "; + break; + case '&': + str += "&"; + break; + case '<': + str += "<"; + break; + case '>': + str += ">"; + break; + default: + str += c; + break; + } + return str; +} + + +// escape what needs escaping +string htmlize(string const & str) { + ostringstream d; + string::const_iterator it = str.begin(); + string::const_iterator en = str.end(); + for (; it != en; ++it) + d << escapeChar(*it); + return d.str(); +} + + +string cleanAttr(string const & str) +{ + string newname; + string::const_iterator it = str.begin(); + string::const_iterator en = str.end(); + for (; it != en; ++it) + newname += isalnum(*it) ? *it : '_'; + return newname; +} + + +docstring cleanAttr(docstring const & str) +{ + docstring newname; + docstring::const_iterator it = str.begin(); + docstring::const_iterator en = str.end(); + for (; it != en; ++it) + if (isalnum(*it)) + newname += *it; + else + newname += '_'; + return newname; +} + + bool isFontTag(string const & s) { return s == "em" || s == "strong"; // others? @@ -86,7 +146,7 @@ docstring StartTag::asTag() const { string output = "<" + tag_; if (!attr_.empty()) - output += " " + attr_; + output += " " + html::htmlize(attr_); output += ">"; return from_utf8(output); } @@ -110,7 +170,7 @@ docstring CompTag::asTag() const { string output = "<" + tag_; if (!attr_.empty()) - output += " " + attr_; + output += " " + html::htmlize(attr_); output += " />"; return from_utf8(output); } @@ -123,7 +183,7 @@ docstring CompTag::asTag() const //////////////////////////////////////////////////////////////// XHTMLStream::XHTMLStream(odocstream & os) - :os_(os) + : os_(os), nextraw_(false) {} @@ -134,8 +194,17 @@ void XHTMLStream::cr() } +void XHTMLStream::writeError(std::string const & s) +{ + LYXERR0(s); + os_ << from_utf8(""); +} + + bool XHTMLStream::closeFontTags() { + if (tag_stack_.empty()) + return true; // first, we close any open font tags we can close StartTag curtag = tag_stack_.back(); while (html::isFontTag(curtag.tag_)) { @@ -155,7 +224,7 @@ bool XHTMLStream::closeFontTags() bool noFontTags = true; for (; it != en; ++it) { if (html::isFontTag(it->tag_)) { - LYXERR0("Font tag `" << it->tag_ << "' still open in closeFontTags()."); + writeError("Font tag `" + it->tag_ + "' still open in closeFontTags()."); noFontTags = false; } } @@ -178,7 +247,11 @@ void XHTMLStream::clearTagDeque() XHTMLStream & XHTMLStream::operator<<(docstring const & d) { clearTagDeque(); - os_ << html::htmlize(d); + if (nextraw_) { + os_ << d; + nextraw_ = false; + } else + os_ << html::htmlize(d); return *this; } @@ -186,7 +259,12 @@ XHTMLStream & XHTMLStream::operator<<(docstring const & d) XHTMLStream & XHTMLStream::operator<<(const char * s) { clearTagDeque(); - os_ << html::htmlize(from_ascii(s)); + docstring const d = from_ascii(s); + if (nextraw_) { + os_ << d; + nextraw_ = false; + } else + os_ << html::htmlize(d); return *this; } @@ -194,7 +272,18 @@ XHTMLStream & XHTMLStream::operator<<(const char * s) XHTMLStream & XHTMLStream::operator<<(char_type c) { clearTagDeque(); - os_ << html::escapeChar(c); + if (nextraw_) { + os_ << c; + nextraw_ = false; + } else + os_ << html::escapeChar(c); + return *this; +} + + +XHTMLStream & XHTMLStream::operator<<(NextRaw const &) +{ + nextraw_ = true; return *this; } @@ -217,11 +306,12 @@ XHTMLStream & XHTMLStream::operator<<(CompTag const & tag) clearTagDeque(); // tabs? os_ << tag.asTag(); + cr(); return *this; } -bool XHTMLStream::isTagOpen(string const & stag) +bool XHTMLStream::isTagOpen(string const & stag) { TagStack::const_iterator sit = tag_stack_.begin(); TagStack::const_iterator const sen = tag_stack_.end(); @@ -260,25 +350,27 @@ XHTMLStream & XHTMLStream::operator<<(EndTag const & etag) for (; dit != den; ++dit) { if (dit->tag_ == etag.tag_) { // it was pending, so we just erase it - LYXERR0("Tried to close pending tag `" << etag.tag_ - << "' when other tags were pending. Tag discarded."); + writeError("Tried to close pending tag `" + etag.tag_ + + "' when other tags were pending. Last pending tag is `" + + pending_tags_.back().tag_ + "'. Tag discarded."); pending_tags_.erase(dit); return *this; } } // so etag isn't itself pending. is it even open? if (!isTagOpen(etag.tag_)) { - LYXERR0("Tried to close `" << etag.tag_ - << "' when tag was not open. Tag discarded."); + writeError("Tried to close `" + etag.tag_ + + "' when tag was not open. Tag discarded."); return *this; } // ok, so etag is open. // our strategy will be as below: we will do what we need to // do to close this tag. - LYXERR0("Closing tag `" << etag.tag_ - << "' when other tags are pending. Discarded pending tags:"); + string estr = "Closing tag `" + etag.tag_ + + "' when other tags are pending. Discarded pending tags:\n"; for (dit = pending_tags_.begin(); dit != den; ++dit) - LYXERR0(dit->tag_); + estr += dit->tag_ + "\n"; + writeError(estr); // clear the pending tags... pending_tags_.clear(); // ...and then just fall through. @@ -296,8 +388,8 @@ XHTMLStream & XHTMLStream::operator<<(EndTag const & etag) // we are trying to close a tag other than the one last opened. // let's first see if this particular tag is still open somehow. if (!isTagOpen(etag.tag_)) { - LYXERR0("Tried to close `" << etag.tag_ - << "' when tag was not open. Tag discarded."); + writeError("Tried to close `" + etag.tag_ + + "' when tag was not open. Tag discarded."); return *this; } @@ -314,8 +406,8 @@ XHTMLStream & XHTMLStream::operator<<(EndTag const & etag) break; if (!html::isFontTag(rit->tag_)) { // we'll just leave it and, presumably, have to close it later. - LYXERR0("Unable to close font tag `" << etag.tag_ - << "' due to open non-font tag `" << rit->tag_ << "'."); + writeError("Unable to close font tag `" + etag.tag_ + + "' due to open non-font tag `" + rit->tag_ + "'."); return *this; } } @@ -350,11 +442,11 @@ XHTMLStream & XHTMLStream::operator<<(EndTag const & etag) // so other tags were opened before this one and not properly closed. // so we'll close them, too. that may cause other issues later, but it // at least guarantees proper nesting. - LYXERR0("Closing tag `" << etag.tag_ - << "' when other tags are open, namely:"); + writeError("Closing tag `" + etag.tag_ + + "' when other tags are open, namely:"); StartTag curtag = tag_stack_.back(); while (curtag.tag_ != etag.tag_) { - LYXERR0(curtag.tag_); + writeError(curtag.tag_); os_ << curtag.asEndTag(); tag_stack_.pop_back(); curtag = tag_stack_.back(); @@ -467,12 +559,12 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf, if (par != pbegin) xs.cr(); - // FIXME Should we really allow anything other than 'p' here? - // If we are already in a paragraph, and this is the first one, then we // do not want to open the paragraph tag. - bool const opened = - (par == pbegin && runparams.html_in_par) ? false : true; + // we also do not want to open it if the current layout does not permit + // multiple paragraphs. + bool const opened = runparams.html_make_pars && + (par != pbegin || !runparams.html_in_par); if (opened) openTag(xs, lay); docstring const deferred = @@ -493,7 +585,7 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf, xs.cr(); } if (!deferred.empty()) { - xs << deferred; + xs << XHTMLStream::NextRaw() << deferred; xs.cr(); } } @@ -522,7 +614,8 @@ ParagraphList::const_iterator makeBibliography(Buffer const & buf, bool isNormalEnv(Layout const & lay) { - return lay.latextype == LATEX_ENVIRONMENT; + return lay.latextype == LATEX_ENVIRONMENT + || lay.latextype == LATEX_BIB_ENVIRONMENT; } @@ -549,8 +642,17 @@ ParagraphList::const_iterator makeEnvironmentHtml(Buffer const & buf, Layout const & style = par->layout(); // the counter only gets stepped if we're in some kind of list, // or if it's the first time through. - if (!style.counter.empty() && (par == pbegin || !isNormalEnv(style))) - buf.params().documentClass().counters().step(style.counter); + // note that enum, etc, are handled automatically. + // FIXME There may be a bug here about user defined enumeration + // types. If so, then we'll need to take the counter and add "i", + // "ii", etc, as with enum. + Counters & cnts = buf.params().documentClass().counters(); + docstring const & cntr = style.counter; + if (!style.counter.empty() + && (par == pbegin || !isNormalEnv(style)) + && cnts.hasCounter(cntr) + ) + cnts.step(cntr); ParagraphList::const_iterator send; // this will be positive, if we want to skip the initial word // (if it's been taken for the label). @@ -569,7 +671,6 @@ ParagraphList::const_iterator makeEnvironmentHtml(Buffer const & buf, closeItemTag(xs, *lastlay); lastlay = 0; } - bool const labelfirst = style.htmllabelfirst(); if (isNormalEnv(style)) { // in this case, we print the label only for the first // paragraph (as in a theorem). @@ -585,12 +686,13 @@ ParagraphList::const_iterator makeEnvironmentHtml(Buffer const & buf, xs.cr(); } } else { // some kind of list + bool const labelfirst = style.htmllabelfirst(); if (!labelfirst) openItemTag(xs, style); if (style.labeltype == LABEL_MANUAL && style.htmllabeltag() != "NONE") { openLabelTag(xs, style); -// sep = par->firstWordLyXHTML(xs, runparams); + sep = par->firstWordLyXHTML(xs, runparams); closeLabelTag(xs, style); xs.cr(); } @@ -603,19 +705,15 @@ ParagraphList::const_iterator makeEnvironmentHtml(Buffer const & buf, } if (labelfirst) openItemTag(xs, style); - else - xs << StartTag("span", "class='" + to_utf8(style.name()) + " inneritem'"); } par->simpleLyXHTMLOnePar(buf, xs, runparams, - text.outerFont(distance(begin, par)), sep); - if (!isNormalEnv(style) && !labelfirst) - xs << EndTag("span"); + text.outerFont(distance(begin, par)), false, sep); ++par; // We may not want to close the tag yet, in particular, // if we're not at the end... if (par != pend // and are doing items... - && style.latextype == LATEX_ITEM_ENVIRONMENT + && !isNormalEnv(style) // and if the depth has changed... && par->params().depth() != origdepth) { // then we'll save this layout for later, and close it when