Commit 5ecdaa88 authored by jan.koester's avatar jan.koester
Browse files

test

parent 80ddab69
Loading
Loading
Loading
Loading
+21 −19
Changes for editor/src/webedit_api.cpp: 21 added lines, 19 removed lines.
Original line number Diff line number Diff line
@@ -3899,7 +3899,7 @@ webedit::Api::PublishCoreResult webedit::Api::publishToConnectionCore(
    autoPublishSurveysForDocument(docXml, authid, blogUrl, domain);

    std::string html = renderTree(doc.root);
    std::string llmsTxt = generateLlmsTxt(doc.root);
    std::string llmsTxt = generateLlmsTxt(doc.root, doc.currentDocName);

    // Build the publish command:
    // [{"authid":"..."}, {"command":"publish","target":"template","html":"...","params":{...}}]
@@ -4744,29 +4744,31 @@ namespace {
    }
}

std::string webedit::Api::generateLlmsTxt(const blogi::webedit::EditPlugin *root) {
std::string webedit::Api::generateLlmsTxt(const blogi::webedit::EditPlugin *root, const std::string &title) {
    if (!root) return "";

    std::vector<std::string> blocks;
    collectLlmsBlocks(root, blocks);

    // llms.txt is expected to be Markdown with at least one H1: promote the
    // first heading found (whatever level) to H1 if the page has headings but
    // none is already top-level.
    bool hasH1 = false;
    int firstHeadingIdx = -1;
    for (size_t i = 0; i < blocks.size(); ++i) {
        if (blocks[i].size() > 1 && blocks[i][0] == '#' && blocks[i][1] == ' ') { hasH1 = true; break; }
        if (firstHeadingIdx < 0 && !blocks[i].empty() && blocks[i][0] == '#') firstHeadingIdx = static_cast<int>(i);
    }
    if (!hasH1 && firstHeadingIdx >= 0) {
        std::string &h = blocks[static_cast<size_t>(firstHeadingIdx)];
        h = "#" + h.substr(h.find_first_not_of('#'));
    }

    std::string out;
    // Empty stays empty (not even a synthesized H1): the publish flow uses an
    // empty llms_txt to mean "this document's text was removed, clear it" —
    // see the comment where this return value is packed into paramsObj below.
    if (blocks.empty()) return "";

    // llms.txt (https://llmstxt.org/) requires an H1 as the file's first
    // line — the spec's only mandatory section, and by convention a single
    // one. Lead with the document's own title rather than scavenging a
    // heading out of the body, so the H1 is always present and always first
    // no matter what widgets the page happens to contain; demote any
    // H1-level block already in the body (e.g. a TextBox styled at the
    // top heading size) to H2 so it doesn't compete with the title.
    for (auto &block : blocks) {
        if (block.size() > 1 && block[0] == '#' && block[1] == ' ')
            block.insert(0, "#");
    }

    std::string out = "# " + (title.empty() ? "Untitled" : title);
    for (const auto &block : blocks) {
        if (!out.empty()) out += "\n\n";
        out += "\n\n";
        out += block;
    }
    return out;
+1 −1
Changes for editor/src/webedit_api.h: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -241,7 +241,7 @@ namespace webedit {
        std::string renderTree(const blogi::webedit::EditPlugin *node);
        std::string exportTreeXml(DocumentState &doc);
        std::string serializeElementXml(blogi::webedit::EditPlugin *node);
        std::string generateLlmsTxt(const blogi::webedit::EditPlugin *root);
        std::string generateLlmsTxt(const blogi::webedit::EditPlugin *root, const std::string &title);
        void persistDocumentStateToSession(const std::string &sessionid, DocumentState &doc);
        void restoreDocumentStateFromSession(const std::string &sessionid, DocumentState &doc);
        void loadDocumentTreeFromXml(DocumentState &doc, const std::string &xml);
+15 −0
Changes for plugins/content/content.cpp: 15 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -132,6 +132,21 @@ namespace blogi {
            }
        }

        void GetLlmsLinks(const int tid,std::vector<blogi::LlmsLink> &links){
            dbpp::SQL sql;
            dbpp::DBResult res;
            sql="SELECT content.slug,content.title,content.descrition FROM content;";
            int ncount=Args->database[tid]->exec(sql,res);
            for(int i=0; i<ncount; ++i){
                blogi::LlmsLink link;
                link.section = "Blog";
                link.title = res[i][1];
                link.url = Args->config->getsiteurl() + "/content/read/" + res[i][0];
                link.description = res[i][2];
                links.push_back(std::move(link));
            }
        }

        void contentIdxPage(const int tid,libhttppp::HttpRequest &curreq,libhtmlpp::HtmlElement *page,const std::string &tag,int start,int end,const std::string &sessionid){            std::string _lang = getLang(*Args->database[tid]);            libhttppp::HTTPException excep;
            libhtmlpp::HtmlString condat;

+35 −0
Changes for plugins/staticpage/static.cpp: 35 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include <iostream>
#include <algorithm>
#include <cctype>

#include <htmlpp/html.h>
#include <htmlpp/exception.h>
@@ -90,6 +91,40 @@ void blogi::StaticPage::GetSiteMap(const int tid,std::map<libhttppp::HttpUrl,std
    }
}

namespace {
    // Static pages have no dedicated title field (just a URL slug), so turn
    // "some-page_name" into "Some Page Name" for the llms.txt link text.
    std::string humanizeSlug(const std::string &slug) {
        std::string title;
        bool startOfWord = true;
        for (char c : slug) {
            if (c == '-' || c == '_') {
                if (!title.empty()) title += ' ';
                startOfWord = true;
                continue;
            }
            title += startOfWord ? static_cast<char>(std::toupper(static_cast<unsigned char>(c))) : c;
            startOfWord = false;
        }
        return title;
    }
}

void blogi::StaticPage::GetLlmsLinks(const int tid,std::vector<blogi::LlmsLink> &links){
    dbpp::SQL sql;
    dbpp::DBResult res;
    sql << "select url,meta from static_content";
    int result = Args->database[tid]->exec(sql,res);
    for(int i=0; i<result; ++i){
        blogi::LlmsLink link;
        link.section = "Pages";
        link.title = humanizeSlug(res[i][0]);
        link.url = Args->config->getsiteurl()+"/staticpage/"+res[i][0];
        link.description = res[i][1];
        links.push_back(std::move(link));
    }
}

json_object* blogi::StaticPage::Settings(const int tid,libhttppp::HttpRequest &req,const std::string &sessionid){
    std::string surl,curl=req.getRequestURL();
    std::string _lang = getLang(*Args->database[tid]);
+1 −0
Changes for plugins/staticpage/static.h: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ namespace blogi {
        const std::string getAuthor();

        void GetSiteMap(const int tid,std::map<libhttppp::HttpUrl,std::chrono::year_month_day> &sitemap);
        void GetLlmsLinks(const int tid,std::vector<blogi::LlmsLink> &links);
        void initPlugin();
        bool haveSettings();

Loading