Added summary to the document tree index
[biaweb2.git] / biawebdocumenttree.hpp
1 #ifndef __BIAWEBDOCUMENTTREE__
2 #define __BIAWEBDOCUMENTTREE__
3 #include <memory>
4 #include <list>
5 #include <iostream>
6 #include <filesystem>
7 #include "biawebdocument.hpp"
8 #include "biawebstrings.hpp"
9
10 // to implement a document tree - both with or without subtrees
11 namespace biaweb {
12 class DocumentTree {
13 protected:
14 // the pointer to the parent tree if there is one or nullptr
15 DocumentTree* parent;
16 // child trees
17 std::list<DocumentTree> children;
18 // title of this tree
19 std::string title;
20 // summary for this tree - this is displayed in the index.html file of
21 // this tree before the list of articles in the tree
22 std::string summary;
23 // file stub of this tree
24 std::string stub;
25 // list of documents in this tree
26 std::list<Document> docs;
27 // set the parent - protected function as this has to be
28 // called only by add_child
29 void set_parent (DocumentTree *parent) {
30 this->parent = parent;
31 }
32
33 public:
34 // create new top level document tree
35 DocumentTree (std::string title, std::string stub = "") {
36 this->title = title;
37 // if stub is not empty set it
38 if (stub != "")
39 this->stub = stub;
40 // make the stub from the title
41 else
42 this->stub = convert_title (title);
43 this->parent = nullptr;
44 }
45
46 // set the summary for this tree
47 void set_summary (std::string summary) {
48 this->summary = summary;
49 }
50
51 // set the summary for this tree as markdown text
52 void set_markdown_summary (std::string summary) {
53 this->summary = convert_to_markdown (summary);
54 }
55
56 std::string get_summary () {
57 return this->summary;
58 }
59
60 // create the document index for this tree
61 void create_tree_html (std::string destdir);
62
63 // set the title
64 void set_title (std::string title) {
65 this->title = title;
66 // if no stub is set
67 if (this->stub == "")
68 this->stub = convert_title (title);
69 }
70
71 void set_stub (std::string stub) {
72 this->stub = stub;
73 }
74
75 std::string get_title () {
76 return this->title;
77 }
78
79 std::string get_stub () {
80 return this->stub;
81 }
82
83 // get the child level of this tree
84 unsigned int get_level ();
85
86 // get the stub hierarchy
87 std::string stub_hierarchy ();
88
89 // add a child tree to this tree
90 void add_child (DocumentTree *child) {
91 child->set_parent (this);
92 this->children.push_back (*child);
93 }
94
95 // add a document to this tree
96 void add_document (Document *doc) {
97 this->docs.push_back (*doc);
98 }
99
100 // print a visual representation of this tree with levels
101 void visualize_tree ();
102
103 // get a pointer to the parent of this tree
104 DocumentTree *get_parent () {
105 return this->parent;
106 }
107 };
108
109 // get the tree level - 0 if top level
110 unsigned int DocumentTree::get_level () {
111 unsigned int lev = 0;
112 DocumentTree *par = this->get_parent ();
113 while (par != nullptr) {
114 lev ++;
115 par = par->get_parent ();
116 }
117 return lev;
118 }
119
120 // get the stub hierarchy for this tree
121 std::string DocumentTree::stub_hierarchy () {
122 std::list<std::string> levels;
123 DocumentTree *par = this->get_parent();
124 while (par!= nullptr) {
125 levels.push_front (par->get_stub());
126 par = par->get_parent ();
127 }
128 std::string stub_str;
129 for (std::string level : levels) {
130 // if stub is empty, don't append a /
131 if (level != "")
132 stub_str += level + "/";
133 }
134 return stub_str;
135 }
136
137 // print the representation of this tree
138 void DocumentTree::visualize_tree () {
139 // print the tree level
140 std::cout << std::setw(3) << std::left << this->get_level ();
141 // indent as per the level
142 for (unsigned int i = 0; i < this->get_level(); i ++)
143 std::cout << "+--";
144 // print the title of this tree
145 std::cout << this->title << std::endl;
146 // recurse through the child trees if any and so on
147 for (DocumentTree child : children)
148 child.visualize_tree ();
149 }
150
151 // create the tree - the index file for this tree and all the documents and
152 // the child trees recursively
153 void DocumentTree::create_tree_html (std::string destdir) {
154 std::unique_ptr<Document> index (new Document (this->title));
155 index.get()->set_index ();
156 // set the file name path
157 std::string filepath = destdir + "/" + this->stub_hierarchy () + this->stub;
158 // set the url path - this should not have destdir as it is not part
159 // of the site tree
160 std::string urlpath = this->stub_hierarchy () + this->stub;
161 // if urlpath is not empty then append a / to the end of the URL. This
162 // is so that the base URL is not absolute
163 if (urlpath != "")
164 urlpath += "/";
165
166 // create the sidebars
167 // First sidebar
168 // Create a link to the index page and
169 // If this tree has a parent, create a sidebar link to the level up
170 std::unique_ptr<SideBar> bar1 (new SideBar());
171 SideBarItem item0;
172 item0.set_sidebar_text (INDEX);
173 item0.set_sidebar_url (urlpath + "index.html");
174 bar1.get()->add_sidebar_item (item0);
175 if (this->get_parent() != nullptr) {
176 SideBarItem item1;
177 item1.set_sidebar_text (GO_UP);
178 item1.set_sidebar_url (this->stub_hierarchy() + "index.html");
179 bar1.get()->add_sidebar_item (item1);
180 }
181 index.get()->add_side_bar (*bar1.get());
182
183 // create a sidebar for the child levels if there are children
184 std::unique_ptr<SideBar> bar2 (new SideBar ());
185 bar2.get()->set_title (SUB_CAT + this->title);
186 for (DocumentTree tree : this->children) {
187 // we use site relative URLs that rely on the base href tag
188 // so for biaweb generated sites, the base href tag should be
189 // used in the main template
190 SideBarItem item (tree.get_title(), urlpath +
191 tree.stub + "/" + "index.html");
192 bar2.get()->add_sidebar_item (item);
193 }
194 index.get()->add_side_bar (*bar2.get());
195
196 // create the path and then the index file
197 std::filesystem::create_directories (filepath);
198
199 // Create the list of documents in this tree with links
200 // Reuse the sidebar class and sidebaritem class which is
201 // basically a list of links but instead of adding a sidebar
202 // add it to the content portion
203 SideBar article_list;
204 article_list.set_title (this->title + ": " + ART_LIST);
205 for (Document doc : this->docs) {
206 SideBarItem item;
207 item.set_sidebar_text (doc.get_title());
208 item.set_sidebar_url (urlpath + doc.get_filename() + ".html");
209 article_list.add_sidebar_item (item);
210 // output the document also, add the side bars
211 if (this->get_parent() != nullptr)
212 doc.add_side_bar (*bar1.get());
213 doc.add_side_bar (*bar2.get());
214 doc.output_to_html (filepath);
215 }
216 index.get()->set_content (this->summary + article_list.to_html());
217
218 index.get()->output_to_html (filepath);
219
220 // create index for children
221 for (DocumentTree tree : this->children)
222 tree.create_tree_html (destdir);
223 }
224 }
225
226 #endif