From f4c8c653a5335929cb55eda8cec0759b681c7873 Mon Sep 17 00:00:00 2001 From: thepra Date: Sun, 2 Apr 2017 18:07:06 +0200 Subject: [PATCH] yei --- TestWebGen.sln | 28 ++ TestWebGen/CTML.h | 10 + TestWebGen/Document.h | 79 ++++++ TestWebGen/EnvironmentScanGrabTool.h | 8 + TestWebGen/EnvironmentScanTool.cpp | 12 + TestWebGen/GeneralBuilder.cpp | 185 +++++++++++++ TestWebGen/GeneralBuilder.h | 28 ++ TestWebGen/Node.h | 359 ++++++++++++++++++++++++++ TestWebGen/ReadMe.txt | 40 +++ TestWebGen/TestWebGen.cpp | 47 ++++ TestWebGen/TestWebGen.vcxproj | 181 +++++++++++++ TestWebGen/TestWebGen.vcxproj.filters | 66 +++++ TestWebGen/ThePraDev.h | 195 ++++++++++++++ TestWebGen/Utilities.h | 108 ++++++++ TestWebGen/packages.config | 4 + TestWebGen/stdafx.cpp | 8 + TestWebGen/stdafx.h | 15 ++ TestWebGen/targetver.h | 8 + TestWebGen/tests.cpp | 96 +++++++ 19 files changed, 1477 insertions(+) create mode 100644 TestWebGen.sln create mode 100644 TestWebGen/CTML.h create mode 100644 TestWebGen/Document.h create mode 100644 TestWebGen/EnvironmentScanGrabTool.h create mode 100644 TestWebGen/EnvironmentScanTool.cpp create mode 100644 TestWebGen/GeneralBuilder.cpp create mode 100644 TestWebGen/GeneralBuilder.h create mode 100644 TestWebGen/Node.h create mode 100644 TestWebGen/ReadMe.txt create mode 100644 TestWebGen/TestWebGen.cpp create mode 100644 TestWebGen/TestWebGen.vcxproj create mode 100644 TestWebGen/TestWebGen.vcxproj.filters create mode 100644 TestWebGen/ThePraDev.h create mode 100644 TestWebGen/Utilities.h create mode 100644 TestWebGen/packages.config create mode 100644 TestWebGen/stdafx.cpp create mode 100644 TestWebGen/stdafx.h create mode 100644 TestWebGen/targetver.h create mode 100644 TestWebGen/tests.cpp diff --git a/TestWebGen.sln b/TestWebGen.sln new file mode 100644 index 0000000..2d1b7de --- /dev/null +++ b/TestWebGen.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestWebGen", "TestWebGen\TestWebGen.vcxproj", "{13843C6A-4801-49A1-98AC-A04441D29730}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {13843C6A-4801-49A1-98AC-A04441D29730}.Debug|x64.ActiveCfg = Debug|x64 + {13843C6A-4801-49A1-98AC-A04441D29730}.Debug|x64.Build.0 = Debug|x64 + {13843C6A-4801-49A1-98AC-A04441D29730}.Debug|x86.ActiveCfg = Debug|Win32 + {13843C6A-4801-49A1-98AC-A04441D29730}.Debug|x86.Build.0 = Debug|Win32 + {13843C6A-4801-49A1-98AC-A04441D29730}.Release|x64.ActiveCfg = Release|x64 + {13843C6A-4801-49A1-98AC-A04441D29730}.Release|x64.Build.0 = Release|x64 + {13843C6A-4801-49A1-98AC-A04441D29730}.Release|x86.ActiveCfg = Release|Win32 + {13843C6A-4801-49A1-98AC-A04441D29730}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/TestWebGen/CTML.h b/TestWebGen/CTML.h new file mode 100644 index 0000000..5b55f83 --- /dev/null +++ b/TestWebGen/CTML.h @@ -0,0 +1,10 @@ +/* + CTML - written by Tinfoilboy + uses the MIT License (https://github.com/tinfoilboy/CFML/blob/master/LICENSE) +*/ +#pragma once +namespace CTML { + static int INDENT_SPACES = 4; +} +#include "Node.h" +#include "Document.h" \ No newline at end of file diff --git a/TestWebGen/Document.h b/TestWebGen/Document.h new file mode 100644 index 0000000..5d8678e --- /dev/null +++ b/TestWebGen/Document.h @@ -0,0 +1,79 @@ +/* + CTML - written by Tinfoilboy + uses the MIT License (https://github.com/tinfoilboy/CFML/blob/master/LICENSE) +*/ +#pragma once +#include "Node.h" +#include +#include + +namespace CTML { + class Document { + // the doctype of this document + Node m_doctype; + // the head tag of this document + Node m_head; + // the body tag of this document + Node m_body; + public: + // the default constructor for a document + Document() { + // create and set the doctype to html + this->m_doctype = Node("", "html"); + this->m_doctype.SetType(NodeType::DOCUMENT_TYPE); + // create the head tag + this->m_head = Node("head"); + // create the body tag + this->m_body = Node("body"); + } + + // add a node to the head element + void AddNodeToHead(Node node) { + this->m_head.AppendChild(node); + } + + // add a node to the body element + void AddNodeToBody(Node node) { + this->m_body.AppendChild(node); + } + + // gets the current document as a string + std::string ToString(const Readability& readability) const { + bool isMultiline = (readability == Readability::MULTILINE || readability == Readability::MULTILINE_BR); + std::string doc = ""; + // add the doctype to the string + doc += m_doctype.ToString(readability, 0); + // every document needs an html tag, add it + doc += ""; + // if we want readability, append a newline to the html beginning tag + doc += ((isMultiline) ? "\n" : ""); + // append the head tag and its children + doc += m_head.ToString(readability, 1) + ((isMultiline) ? "\n" : ""); + // append the body tag and its children + doc += m_body.ToString(readability, 1) + ((isMultiline) ? "\n" : ""); + // close the html tag + doc += ""; + return doc; + } + + // get the current document as a tree represented in a string + std::string ToTree() const { + std::string treeStr = ""; + treeStr += "html\n"; + treeStr += m_head.GetTreeString(0); + treeStr += m_body.GetTreeString(0); + return treeStr; + } + + // write the current document to a file + bool WriteToFile(const std::string& filePath, const Readability& readability) const { + std::ofstream file(filePath.c_str()); + if (file.is_open()) { + file << this->ToString(readability); + file.close(); + return true; + } + return false; + } + }; +} \ No newline at end of file diff --git a/TestWebGen/EnvironmentScanGrabTool.h b/TestWebGen/EnvironmentScanGrabTool.h new file mode 100644 index 0000000..8521183 --- /dev/null +++ b/TestWebGen/EnvironmentScanGrabTool.h @@ -0,0 +1,8 @@ +#pragma once +class EnvironmentScanGrabTool +{ +public: + EnvironmentScanGrabTool(); + ~EnvironmentScanGrabTool(); +}; + diff --git a/TestWebGen/EnvironmentScanTool.cpp b/TestWebGen/EnvironmentScanTool.cpp new file mode 100644 index 0000000..8dbbc4d --- /dev/null +++ b/TestWebGen/EnvironmentScanTool.cpp @@ -0,0 +1,12 @@ +#include "stdafx.h" +#include "EnvironmentScanGrabTool.h" + + +EnvironmentScanGrabTool::EnvironmentScanGrabTool() +{ +} + + +EnvironmentScanGrabTool::~EnvironmentScanGrabTool() +{ +} diff --git a/TestWebGen/GeneralBuilder.cpp b/TestWebGen/GeneralBuilder.cpp new file mode 100644 index 0000000..c0a5287 --- /dev/null +++ b/TestWebGen/GeneralBuilder.cpp @@ -0,0 +1,185 @@ +#pragma once +#include "stdafx.h" +#include "GeneralBuilder.h" +#include "ThePraDev.h" + +GeneralBuilder::GeneralBuilder() +{ +} + + +GeneralBuilder::~GeneralBuilder() +{ +} + +list GeneralBuilder::BuildThePraSite(Sites site) +{ + Utilities tool{Utilities()}; + string cPath{tool.GetCurrentPath()}; + switch (site) + { + case DEV: + { + ThePraDev a{ThePraDev()}; + string link = "https://www.thepra-dev.com/", html = ".html"; + + Document index = Document(); + Head(index, link + "index" + html, "ThePra WebSite"); + Body(index, cPath + a.contentLinks[0], site); + + Document code = Document(); + Head(code, link + "code" + html, "ThePra Code"); + Body(code, cPath + a.contentLinks[1], site); + + Document blog = Document(); + Head(blog, link + "blog" + html, "ThePra Blog"); + Body(blog, cPath + a.contentLinks[2], site); + + Document about = Document(); + Head(about, link + "about" + html, "ThePra About"); + Body(about, cPath + a.contentLinks[3], site); + + Document contact = Document(); + Head(contact, link + "contact" + html, "ThePra Contact"); + Body(contact, cPath + a.contentLinks[4], site); + + return{index,code,blog,about,contact}; + } + break; + case ART: + { + string link = "http://art.thepra-dev.com/", html = ".html"; + + Document index = Document(); + Head(index, link + "index" + html, "title"); + Body(index, cPath, site); + + Document aboutme = Document(); + Head(aboutme, link + "aboutme" + html, "title"); + Body(aboutme, cPath, site); + + Document twitch = Document(); + Head(twitch, link + "twitch" + html, "title"); + Body(twitch, cPath, site); + + Document twitter = Document(); + Head(twitter, link + "twitter" + html, "title"); + Body(twitter, cPath, site); + + Document youtubePosts = Document(); + Head(youtubePosts, link + "youtubePosts" + html, "title"); + Body(youtubePosts, cPath, site); + + return{index,aboutme,twitch,twitter,youtubePosts}; + } + break; + default: + break; + } + return list(); +} + +void GeneralBuilder::Head(Document &file, + string canonicalURL, + string title, + Levels level, + string description, + list cssStyles) +{ + string whichLevel = ChooseLevel(level); + // ESSENTIAL + Node charset = Node(meta).SetAttribute("charset", "utf-8").UseClosingTag(false); + Node edge = Node(meta).SetAttribute(http_equiv, "x-ua-compatible").SetAttribute(content, "ie=edge").UseClosingTag(false); + Node viewport = Node(meta).SetAttribute(name, "viewport").SetAttribute(content, "width=device-width, initial-scale=1").UseClosingTag(false); + Node titleP = Node("title", title); + // OTHER + Node canon = Node(link).SetAttribute(rel, "canonical").SetAttribute(href, canonicalURL).UseClosingTag(false); + Node base = Node("base").SetAttribute(href, canonicalURL).UseClosingTag(false); + Node contentSecurityPolicy = Node(meta).SetAttribute(http_equiv, "Content-Security-Policy").SetAttribute(content, "default-src 'self'").UseClosingTag(false); + Node descriptionP = Node(meta).SetAttribute(name, "description").SetAttribute(content, description).UseClosingTag(false); + Node robots = Node(meta).SetAttribute(name, "robots").SetAttribute(content, "index,follow,noodp").UseClosingTag(false); + Node googleBot = Node(meta).SetAttribute(name, "googlebot").SetAttribute(content, "index,follow").UseClosingTag(false); + Node referrer = Node(meta).SetAttribute(name, "referrer").SetAttribute(content, "no-referrer").UseClosingTag(false); + Node icon = Node(link).SetAttribute(rel, "icon").SetAttribute(href, whichLevel + "icon/favicon.png").SetAttribute("type", "image/png").UseClosingTag(false); + + file.AddNodeToHead(charset); + file.AddNodeToHead(edge); + file.AddNodeToHead(viewport); + file.AddNodeToHead(titleP); + file.AddNodeToHead(base); + file.AddNodeToHead(canon); + if (cssStyles.front() == "") + { + Node style = Node(link).SetAttribute(rel, "stylesheet").SetAttribute(href, whichLevel + "style.css").UseClosingTag(false); + file.AddNodeToHead(style); + } + else + { + for each (string s in cssStyles) + { + Node style = Node(link).SetAttribute(rel, "stylesheet").SetAttribute(href, whichLevel + s).UseClosingTag(false); + file.AddNodeToHead(style); + } + } + file.AddNodeToHead(contentSecurityPolicy); + file.AddNodeToHead(descriptionP); + file.AddNodeToHead(robots); + file.AddNodeToHead(googleBot); + file.AddNodeToHead(referrer); + file.AddNodeToHead(icon); +} + + +void GeneralBuilder::Body(Document &file, string cPath, Sites site, PageType type) +{ + switch (site) + { + case DEV: + { + ThePraDev::BuildBody(file, cPath, ROOT, type); + } + case ART: + { + + } + + default:// I'm drunk + break; + } +} + +void GeneralBuilder::BuildHTMLFiles(Sites site, list rootFiles, list postFiles) +{ + string cDevOutputPath{Utilities::GetCurrentPath() + "\\output_thepradev\\"}; + string postcDevOutputPath{cDevOutputPath + "postsContent\\"}; + path dir = current_path(); + cout << dir.string() << endl; + for (auto& p : directory_iterator(dir)) + { + path asd = p.path(); + + if (!is_directory(p)) + cout << p.path().filename().string() << endl; + } + switch (site) + { + case Utilities::DEV: + { + dir.append("thepradev"); + path contentDir{dir.append("content")}; + path postsContentDir{dir.append("postsContent")}; + + } + break; + case Utilities::ART: + { + dir.append("thepraart\\"); + + } + break; + default: + break; + } + +} + diff --git a/TestWebGen/GeneralBuilder.h b/TestWebGen/GeneralBuilder.h new file mode 100644 index 0000000..a61daf1 --- /dev/null +++ b/TestWebGen/GeneralBuilder.h @@ -0,0 +1,28 @@ +#pragma once +#include "CTML.h" +#include +#include +#include "Utilities.h" +#include +using namespace CTML; +using namespace std; + +class GeneralBuilder : Utilities +{ +public: + GeneralBuilder(); + ~GeneralBuilder(); + list BuildThePraSite(Sites site); + void Head(Document &file, + string canonicalURL, + string title, + Levels level = ROOT, + string description = "", + list cssStyles = {""}); + void Body(Document &file, + string cPath, + Sites site, + PageType type = NORMAL); + void BuildHTMLFiles(Sites site, list rootFiles, list postFiles = {{}}); +}; + diff --git a/TestWebGen/Node.h b/TestWebGen/Node.h new file mode 100644 index 0000000..b7ac8a6 --- /dev/null +++ b/TestWebGen/Node.h @@ -0,0 +1,359 @@ +/* + CTML - written by Tinfoilboy + uses the MIT License (https://github.com/tinfoilboy/CFML/blob/master/LICENSE) +*/ +#pragma once +#include +#include +#include +#include +#include + +namespace CTML { + // the types of nodes used for the html + // DOCUMENT_TYPE doesn't use the element name, but uses + // the content to determine the document type to use + // ELEMENT is just a normal element + enum class NodeType { DOCUMENT_TYPE, ELEMENT }; + + // a few enums for readability of the HTML + // SINGLE_LINE returns the string as one line + // MULTILINE returns the string as multiple lines, which is good for file outputs or readability. + // MULTILINE_BR is essentially the same as MULTILINE, but the difference is that newlines in the content of the node are formatted to use
tags. + enum class Readability { SINGLE_LINE, MULTILINE, MULTILINE_BR }; + + // the state of the Node name parser + // NONE means that nothing is being parsed + // CLASS means that a class attribute is being parsed + // ID means that an ID is being parsed for the node + enum class NodeParser { NONE, CLASS, ID }; + + class Node { + // the type of node this + NodeType m_type; + // the name of this node, e.g. div, a, span, e.t.c. + std::string m_name; + // the classes for this node + std::string m_classes; + // the ids for this node + std::string m_id; + // the content of this node + std::string m_content; + // determines whether or not to add a closing tag (ie. ) + // if this is false, it also doesn't add content to the tag + // as there is nowhere to place content + bool m_closeTag = true; + // the child elements of this node + std::vector m_children; + // an unordered_map of attributes, name is the attribute name and the value is the attribute value + std::unordered_map m_attributes; + public: + // default constructor, does nothing + Node() = default; + + // create a node with the name specified + Node(const std::string& name) { + this->m_type = NodeType::ELEMENT; + this->SetName(name); + } + + // create a node with the name specified, also containing the following content + Node(const std::string& name, const std::string& content) { + this->m_type = NodeType::ELEMENT; + this->SetName(name); + this->m_content = content; + } + + // return this node as an html string + std::string ToString(Readability readability, int indentLevel) const { + // the element string that will be returned + std::string elem = ""; + // the four space indent. + std::string indent = ""; + std::string indentContent = ""; + // if the readabilty points is either multiline types, this would be true + bool isMultiline = (readability == Readability::MULTILINE || readability == Readability::MULTILINE_BR); + // increment the indent string by four spaces based on the indentLevel + // but only if the readabilty is MULTILINE OR MULTILINE_BR + if (isMultiline) { + for (int i = 0; i < indentLevel; i++) { + indent = std::string(INDENT_SPACES * indentLevel, ' '); + } + // set the m_content indent level to the indent level plus four more spaces + indentContent = std::string(INDENT_SPACES * (indentLevel + 1), ' '); + } + if (this->m_type == NodeType::ELEMENT) { + // construct the first part of the element string, the tag beginning + elem = ((isMultiline) ? indent : "") + "<" + m_name + ""; + // add the class list if it isn't empty + if (!m_classes.empty()) { + std::string classTag = "class=\""; + elem += " " + classTag + m_classes + "\""; + } + // add the id list if it isn't empty + if (!m_id.empty()) { + std::string idTag = "id=\""; + elem += " " + idTag + m_id + "\""; + } + // make an iterator for each attribute + for (const auto& attr : m_attributes) { + elem += " " + attr.first + "=\"" + attr.second + "\""; + } + // close the beginning tag + elem += ">"; + // only add the content, as well as the closing tag if it is + // specified to do so + if (m_closeTag) + { + // if multiline is specified and the content/children aren't empty, add a newline + if (isMultiline && (!m_content.empty() || !m_children.empty())) + elem += "\n"; + // if we have m_content to append + if (!m_content.empty()) { + // format the elements content based on the readability, as well as the indent level for content + elem += _GetFormattedContent(readability, indentContent); + } + // get every child node from the m_children list + for (std::size_t i = 0; i < m_children.size(); ++i) { + const auto& childNode = m_children[i]; + // append the child node to the elem string. + // if this is not the last child node append a newline if multiline + elem += childNode.ToString(readability, indentLevel + 1) + ((i != m_children.size() - 1 && isMultiline) ? "\n" : ""); + } + // if multiline is specified and the content/children aren't empty, add a newline and indent + elem += ((isMultiline && (!m_content.empty() || !m_children.empty())) ? "\n" + indent : "") + ""; + } + } + else if (this->m_type == NodeType::DOCUMENT_TYPE) { + // just construct the docm_type from the m_content given, if readability is wanted, add a newline + elem += "" + ((isMultiline) ? "\n" : ""); + } + return elem; + } + + std::string GetTreeString(int indentLevel) const { + // the tree string + std::string tree; + // indent level + std::string indent(INDENT_SPACES * indentLevel, ' '); + // turn the class list into actual classes for the elements + std::string classList = m_classes; + std::replace(classList.begin(), classList.end(), ' ', '.'); + // if the class list isn't empty, prepend a period + if (!classList.empty()) + classList = '.' + classList; + // add the current element to the tree + tree += indent + " |_ " + this->m_name + classList + '\n'; + // for each child + for (const auto& child : m_children) { + tree += child.GetTreeString(indentLevel + 1) + '\n'; + } + return tree; + } + + Node& SetName(const std::string& name) { + // the index of a period + const auto periodIndex = name.find('.'); + // the index of a pound sign + const auto poundIndex = name.find('#'); + // if there are classes in the name + if (periodIndex != std::string::npos || poundIndex != std::string::npos) { + // if the pound index comes before the period index + bool poundBefore = (poundIndex != std::string::npos && poundIndex < periodIndex); + // get the first index for parsing + // if pound comes first, or there are no periods, use the first pound index first + // else use the first period index + const auto ind = ((poundBefore || (periodIndex == std::string::npos && poundIndex != std::string::npos)) ? poundIndex : periodIndex); + // get the element name + std::string elemName = name.substr(0, ind); + // parse the current ids and classes + _ParseClassesAndIDS(name.substr(ind)); + // set the element name to the built element name + this->m_name = elemName; + } + else { + this->m_name = name; + } + return *this; + } + + std::string GetAttribute(const std::string& name) const { + // the class attribute is tracked with m_classes, so we return that instead of m_attributes[name] + if (name != "class" && name != "id" && m_attributes.count(name) > 0) + return m_attributes.at(name); + else if (name == "class") + return m_classes; + else if (name == "id") + return m_id; + else + return ""; + } + + std::string GetSelector() const { + std::string classesPeriod = _ReplaceAllOccurrences(m_classes, " ", "."); + return m_name + classesPeriod + "#" + m_id; + } + + Node& SetAttribute(std::string name, std::string value) { + // setting the "class" attribute would make there be two class attributes on the element + // so therefore, if the name of this is class, we just override "m_classes" + if (name != "class" && name != "id") + m_attributes[name] = value; + else if (name == "class") + m_classes = value; + else if (name == "id") + m_id = value; + return *this; + } + + Node& SetType(NodeType type) { + this->m_type = type; + return *this; + } + + Node& SetContent(const std::string& text) { + this->m_content = text; + return *this; + } + + Node& ToggleClass(const std::string& className) { + size_t findIndex = m_classes.find(className); + if (findIndex == std::string::npos) { + // append the class + m_classes += ((!m_classes.empty()) ? " " : "") + className; + } + else { + // remove the class + m_classes.erase(findIndex, className.size()); + } + return *this; + } + + Node& AppendChild(Node child) { + m_children.push_back(child); + return *this; + } + + Node& UseClosingTag(bool close) { + this->m_closeTag = close; + return *this; + } + + private: + std::string _GetFormattedContent(Readability readability, const std::string& indent) const { + std::string result; + std::istringstream iss(m_content); + // if we are using either variant of multiple lines, run this. + if (readability == Readability::MULTILINE || readability == Readability::MULTILINE_BR) { + // the newline string, differs between MULTILINE and MULTILINE_BR + std::string newline = ((readability == Readability::MULTILINE_BR) ? "\n" + indent + "
\n" : "\n"); + // the current line iterated + int curLine = 0; + // iterate through each line in this node + for (std::string line; std::getline(iss, line);) + { + result += ((curLine > 0) ? newline : "") + indent + line; + curLine++; + } + } + else { + // iterate through each line in this node + for (std::string line; std::getline(iss, line);) + { + result += line; + } + } + // replaces all instances of "<" in the content with "<", to escape rogue HTML + //result = _ReplaceAllOccurrences(result, "<", "<"); + // replaces all instances of ">" in the content with ">" to escape rogue HTML + //result = _ReplaceAllOccurrences(result, ">", ">"); + // return the result of the content + return result; + } + std::string _ReplaceAllOccurrences(std::string replacer, const std::string& replacable, const std::string& replace) const { + // the start of the current replacable string + size_t start = 0; + // try and find each occurrence of replaceable until it can't be found + while ((start = replacer.find(replacable, start)) != std::string::npos) { + // replace the actual string + replacer.replace(start, replacable.length(), replace); + // add to the start so that find can be run again + start += replace.length(); + } + // return the replaced string + return replacer; + } + int _CountOccurrences(std::string finder, const std::string& findable) const { + // the occurrences of the string + int occurrences = 0; + // the start of the current replacable string + size_t start = 0; + // try and find each occurrence of replaceable until it can't be found + while ((start = finder.find(findable, start)) != std::string::npos) { + // replace the actual string + occurrences++; + // add to the start so that find can be run again + start += findable.length(); + } + // return the replaced string + return occurrences; + } + void _ParseClassesAndIDS(std::string classesAndIDs) { + // what is currently being parsed + // zero for nothing + // one for class + // two for id + NodeParser currentlyParsing = NodeParser::NONE; + // the string for the class or ID + std::string attrString; + // iterate through each character in the string + for (unsigned int i = 0; i < classesAndIDs.size(); i++) { + // the current character being iterated + char curChar = classesAndIDs[i]; + if (currentlyParsing == NodeParser::NONE) { + // if the current character is a period, set the current parsing to class + // else if the current character is a pound sign, set the current parsing to id + if (curChar == '.') { + currentlyParsing = NodeParser::CLASS; + } + else if (curChar == '#') { + currentlyParsing = NodeParser::ID; + } + } + else { + // if the current character is a period, set the current parsing to class + // else if the current character is a pound sign, set the current parsing to id + if (curChar == '.' || curChar == '#') { + if (currentlyParsing == NodeParser::CLASS) + m_classes += attrString + " "; + else + // if we hit an id, we just reset the id + // this is because HTML only allows for a single id on each element + m_id = attrString; + attrString.clear(); + currentlyParsing = ((curChar == '.') ? NodeParser::CLASS : NodeParser::ID); + } + else { + // add the current character to the class or id string + attrString += curChar; + } + } + // if we are at the last character, and are still parsing something, add it to the respective attr + if (currentlyParsing != NodeParser::NONE && i == classesAndIDs.size() - 1) { + if (currentlyParsing == NodeParser::CLASS) + m_classes += attrString; + else + // if we hit an id, we just reset the id + // this is because HTML only allows for a single id on each element + m_id = attrString; + attrString.clear(); + } + } + // if there is an extra space at the end of m_classes, remove it + if (!m_classes.empty()) { + if (isspace(m_classes.at(m_classes.size() - 1))) + m_classes = m_classes.substr(0, m_classes.size() - 1); + } + } + }; +} \ No newline at end of file diff --git a/TestWebGen/ReadMe.txt b/TestWebGen/ReadMe.txt new file mode 100644 index 0000000..bc0f03f --- /dev/null +++ b/TestWebGen/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + CONSOLE APPLICATION : TestWebGen Project Overview +======================================================================== + +AppWizard has created this TestWebGen application for you. + +This file contains a summary of what you will find in each of the files that +make up your TestWebGen application. + + +TestWebGen.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +TestWebGen.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +TestWebGen.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named TestWebGen.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/TestWebGen/TestWebGen.cpp b/TestWebGen/TestWebGen.cpp new file mode 100644 index 0000000..fba231d --- /dev/null +++ b/TestWebGen/TestWebGen.cpp @@ -0,0 +1,47 @@ +// TestWebGen.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include +#include "GeneralBuilder.h" +#include +#include +#include "Utilities.h" +#include "ThePraDev.h" + +using namespace std::experimental::filesystem::v1; + + +using namespace std; +using namespace CTML; + + +int main() +{ + ThePraDev n{ThePraDev()}; + string cDevOutputPath{Utilities::GetCurrentPath()+ "\\output_thepradev\\"}; + string postcDevOutputPath{cDevOutputPath + "postsContent\\"}; + path dir = canonical("."); + cout << dir.append("thepradev").append("a")< wholeSite = list(); + GeneralBuilder dev; + wholeSite = dev.BuildThePraSite(Utilities::DEV); + for each (Document page in wholeSite) + { + page.WriteToFile(cDevOutputPath + n.pages[i++], Readability::MULTILINE); + }*/ + cout << "DONE"; + getchar(); + return 0; +} + diff --git a/TestWebGen/TestWebGen.vcxproj b/TestWebGen/TestWebGen.vcxproj new file mode 100644 index 0000000..f903e9b --- /dev/null +++ b/TestWebGen/TestWebGen.vcxproj @@ -0,0 +1,181 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {13843C6A-4801-49A1-98AC-A04441D29730} + Win32Proj + TestWebGen + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + NotUsing + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + C:\Program Files\boost\boost_1_63_0;%(AdditionalIncludeDirectories) + true + + + Console + true + C:\Program Files\boost\boost_1_63_0\libs\filesystem;%(AdditionalLibraryDirectories) + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/TestWebGen/TestWebGen.vcxproj.filters b/TestWebGen/TestWebGen.vcxproj.filters new file mode 100644 index 0000000..298995c --- /dev/null +++ b/TestWebGen/TestWebGen.vcxproj.filters @@ -0,0 +1,66 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + \ No newline at end of file diff --git a/TestWebGen/ThePraDev.h b/TestWebGen/ThePraDev.h new file mode 100644 index 0000000..77a2e99 --- /dev/null +++ b/TestWebGen/ThePraDev.h @@ -0,0 +1,195 @@ +#pragma once +#include "Utilities.h" +#include +#include + +class ThePraDev : Utilities +{ +public: + string index = "index.html"; + string code = "code.html"; + string blog = "blog.html"; + string about = "about.html"; + string contact = "contact.html"; + + string Home = "Home"; + string Code = "Code"; + string Blog = "Blog"; + string About = "About"; + string Contact = "Contact"; + string Menu = "Menu"; + string contentFolder = "\\thepradev\\content\\"; + string contentLinks[5]{ + contentFolder + "index.txt", + contentFolder + "code.txt", + contentFolder + "blog.txt", + contentFolder + "about.txt", + contentFolder + "contact.txt" + }; + string pages[5]{ + "index.html", + "code.html", + "blog.html", + "about.html", + "contact.html" + }; + + static void BuildBody(Document &file,string cPath, Levels level, PageType ptype = NORMAL); + +private: + static list NavigationBar(Levels level, DeskOrMob mtype); + static list SingleMainContent(Levels level,string cPath, DeskOrMob mtype, list content = {""}); + static Node Extra(Levels level); + static Node Player(Levels level); +}; + + +inline void ThePraDev::BuildBody(Document &file,string cPath, Levels level, PageType ptype) +{ + list navBar = NavigationBar(level, D); + list navBarM = NavigationBar(level, M); + list main = SingleMainContent(level, cPath, D); + list mainM = SingleMainContent(level, cPath, M); + + Node desktop = Node("section#desktop"); + Node mobile = Node("section#mobile"); + + for each (Node item in navBar) + { + desktop.AppendChild(item); + } + for each (Node item in navBarM) + { + mobile.AppendChild(item); + } + for each (Node item in main) + { + desktop.AppendChild(item); + } + for each (Node item in mainM) + { + mobile.AppendChild(item); + } + + file.AddNodeToBody(desktop); + file.AddNodeToBody(mobile); +} + +inline list ThePraDev::NavigationBar(Levels level, DeskOrMob mtype) +{ + ThePraDev a; + string whichLevel = ChooseLevel(level); + switch (mtype) + { + case D: + { + Node elem0 = Node("div.navigation_bar"); + Node elem1 = Node("img").SetAttribute(a.src, whichLevel + "icon/up.png").SetAttribute(a.alt, "Upper Decoration").UseClosingTag(false); + Node elem2 = Node("ul.bortrr.borbrr"); + Node elem3 = Node("li.bortrr").AppendChild(Node(a.a, a.Home).SetAttribute(a.href, whichLevel + a.index)); + Node elem4 = Node(a.li).AppendChild(Node(a.a, a.Code).SetAttribute(a.href, whichLevel + a.code)); + Node elem5 = Node(a.li).AppendChild(Node(a.a, a.Blog).SetAttribute(a.href, whichLevel + a.blog)); + Node elem6 = Node(a.li).AppendChild(Node(a.a, a.About).SetAttribute(a.href, whichLevel + a.about)); + Node elem7 = Node(a.li).AppendChild(Node(a.a, a.Contact).SetAttribute(a.href, whichLevel + a.contact)); + Node elem8 = Extra(level); + Node elem9 = Node("img").SetAttribute(a.src, whichLevel + "icon/down.png").SetAttribute(a.alt, "Down Decoration").UseClosingTag(false); + + elem0.AppendChild(elem1) + .AppendChild(elem2 + .AppendChild(elem3) + .AppendChild(elem4) + .AppendChild(elem5) + .AppendChild(elem6) + .AppendChild(elem7) + .AppendChild(elem8)) + .AppendChild(elem9); + + return{{elem0}}; + } + break; + case M: + { + Node elem0 = Node("div.navigation_barm"); + Node elem1 = Node("img.immagini_laterali").SetAttribute(a.src, whichLevel + "icon/left.png").SetAttribute(a.alt, "Upper Left Decoration").UseClosingTag(false); + Node elem2 = Node("div.navigation_barminner"); + + Node elem3 = Node("nav._nav"); + Node elem4 = Node("laber.toggle").SetAttribute("for", "drop").SetContent(a.Menu); + Node elem5 = Node("input#drop").SetAttribute("type", "checkbox").UseClosingTag(false); + Node elem6 = Node("ul.menu"); + Node elem7 = Node(a.li).AppendChild(Node(a.a, a.Home).SetAttribute(a.href, whichLevel + a.index)); + Node elem8 = Node(a.li).AppendChild(Node(a.a, a.Code).SetAttribute(a.href, whichLevel + a.code)); + Node elem9 = Node(a.li).AppendChild(Node(a.a, a.Blog).SetAttribute(a.href, whichLevel + a.blog)); + Node elem10 = Node(a.li).AppendChild(Node(a.a, a.About).SetAttribute(a.href, whichLevel + a.about)); + Node elem11 = Node(a.li).AppendChild(Node(a.a, a.Contact).SetAttribute(a.href, whichLevel + a.contact)); + + Node elem12 = Node("img.immagini_laterali").SetAttribute(a.src, whichLevel + "icon/right.png").SetAttribute(a.alt, "Upper Right Decoration").UseClosingTag(false); + + elem0.AppendChild(elem1) + .AppendChild(elem2 + .AppendChild(elem3 + .AppendChild(elem4) + .AppendChild(elem5) + .AppendChild(elem6 + .AppendChild(elem7) + .AppendChild(elem8) + .AppendChild(elem9) + .AppendChild(elem10) + .AppendChild(elem11)))) + .AppendChild(elem12); + + return{{elem0}}; + } + break; + default: return{{}}; + break; + } + +} + +inline list ThePraDev::SingleMainContent(Levels level,string cPath, DeskOrMob mtype, list content) +{ + ThePraDev a; + string whichLevel = ChooseLevel(level); + Node mainC = Node("div#main"); + Node mainMC = mainC; + string STRING; + string contentDesktop = ""; + string contentMobile = ""; + + FullFillContent(cPath, &contentDesktop, &contentMobile); + + mainC.SetContent(contentDesktop); + mainMC.SetContent(contentMobile); + /*for each (string item in contentTest) + { + mainC.SetContent(item+"\n"); + }*/ + if (mtype == D) + return{mainC}; + else return{mainMC}; +} +inline Node ThePraDev::Extra(Levels level) +{ + ThePraDev a; + string whichLevel = ChooseLevel(level); + Node extra = Node("li.borbrr") + .AppendChild(Node(a.a, "+ Extra +")) + .AppendChild(Node("ul.borbrr") + .AppendChild(Node("li.colbk") + .AppendChild(Node("img.fiximgmenu").SetAttribute(a.src, whichLevel + "icon/signbot.gif").SetAttribute(a.alt, "MotD").UseClosingTag(false))) + .AppendChild(Node(a.li) + .AppendChild(Player(level)))); + return extra; +} + +inline Node ThePraDev::Player(Levels level) +{ + ThePraDev a; + string whichLevel = ChooseLevel(level); + Node player = Node("div.player") + .AppendChild(Node("audio").SetAttribute("controls", "controls").SetAttribute("preload", "auto") + .AppendChild(Node("source").SetAttribute(a.src, whichLevel + "videoplayback.ogg").SetAttribute("type", "audio/ogg").SetContent("Your browser does not support the audio element."))); + return player; +} + diff --git a/TestWebGen/Utilities.h b/TestWebGen/Utilities.h new file mode 100644 index 0000000..2d8915c --- /dev/null +++ b/TestWebGen/Utilities.h @@ -0,0 +1,108 @@ +#pragma once +#include +#include +#include +#include +using namespace std; +using namespace std::experimental::filesystem::v1; + +class Utilities +{ +protected: + const string meta = "meta"; + const string link = "link"; + const string rel = "rel"; + const string href = "href"; + const string http_equiv = "http-equiv"; + const string content = "content"; + const string name = "name"; + const string li = "li"; + const string ul = "ul"; + const string a = "a"; + const string src = "src"; + const string alt = "alt"; + +public: + static enum DeskOrMob + { + D, //Desktop part of the page + M //Mobile part of the page + }; + DeskOrMob setDM = D; + enum Levels + { + ROOT,//Content at the index.html directory level + LEVEL1,//Content at the first directory + LEVEL2//Content at the second directory + }; + enum Sites + { + DEV,//Build the thepra-dev.com + ART//Build the art.thepra-dev.com + }; + enum PageType + { + NORMAL, + POST + }; + + static string ChooseLevel(Levels level); + static void FullFillContent(string link, string* desktop, string* mobile); + static string GetCurrentPath(); +}; + +inline string Utilities::ChooseLevel(Levels level) +{ + switch (level) + { + case Utilities::ROOT:return ""; + break; + case Utilities::LEVEL1:return "../"; + break; + case Utilities::LEVEL2:return "../../"; + default:return ""; + break; + } +} + +inline void Utilities::FullFillContent(string link, string* desktop, string* mobile) +{ + + //link = "C:\\content\\index.txt"; //TODO find out a general way to scan the folder env + Utilities a = Utilities(); + string line = ""; + std::ifstream infile; + infile.open(link); + while (!infile.eof()) + { + std::getline(infile, line); + if (line == "desktop") + { + line = ""; + a.setDM = D; + } + if (a.setDM == D) + { + if (line == "mobile") + { + line = ""; + a.setDM = M; + } + *desktop += line + "\n"; + } + if (a.setDM == M) + { + *mobile += line + "\n"; + } + } + infile.close(); +} + +inline string Utilities::GetCurrentPath() +{ + path current = current_path(); + string pathString = current.string(); + //cout << pathString << endl; + return pathString; +} + diff --git a/TestWebGen/packages.config b/TestWebGen/packages.config new file mode 100644 index 0000000..f5b1c4a --- /dev/null +++ b/TestWebGen/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/TestWebGen/stdafx.cpp b/TestWebGen/stdafx.cpp new file mode 100644 index 0000000..998b52c --- /dev/null +++ b/TestWebGen/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// TestWebGen.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/TestWebGen/stdafx.h b/TestWebGen/stdafx.h new file mode 100644 index 0000000..b005a83 --- /dev/null +++ b/TestWebGen/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: reference additional headers your program requires here diff --git a/TestWebGen/targetver.h b/TestWebGen/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/TestWebGen/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/TestWebGen/tests.cpp b/TestWebGen/tests.cpp new file mode 100644 index 0000000..38dfead --- /dev/null +++ b/TestWebGen/tests.cpp @@ -0,0 +1,96 @@ +#include "stdafx.h" +#include +#include "CTML.h" +#include + +// std chrono has the worst namespace abuse i've ever seen, so therefore, i'm typedeffing +typedef std::chrono::high_resolution_clock high_res_clock; +typedef std::chrono::milliseconds millis; + +using namespace CTML; + +// tests if two strings are equivelent to each other +bool assert_strings_equal(const std::string& left, const std::string& right) { + return (left == right); +} + +// this test ensures that HTML inside of the content is escaped correctly. +void run_escape_test() { + // what the node's to string should be equal to + const auto htmlString = "<script>alert(\"ha ha hacked!\")</script>"; + Node node("a.button", ""); + // the node's string output + const auto nodeString = node.ToString(Readability::SINGLE_LINE, 0); + auto test = assert_strings_equal(htmlString, nodeString); + std::cout << "Escape Test " << ((test) ? "passed!" : "failed!") << std::endl << + "HTML Output: " << nodeString << std::endl << + // use a double end line at the end for spacing between tests + "Expected Output: " << htmlString << std::endl << std::endl; +} + +// this test ensures that the HTML document created is equal to a correct HTML5 document +void run_document_test() { + // what the document's to string should be equal to + const auto htmlString = "

<test!>

"; + Document doc; + // the string output of the document + doc.AddNodeToBody(Node("h1", "")); + const auto docString = doc.ToString(Readability::SINGLE_LINE); + auto test = assert_strings_equal(htmlString, docString); + std::cout << "Document Test " << ((test) ? "passed!" : "failed!") << std::endl << + "HTML Output: " << docString << std::endl << + // use a double end line at the end for spacing between tests + "Expected Output: " << htmlString << std::endl << std::endl; +} + +// this test checks if the classes provided are correctly stored +void run_class_test() { + const auto classString = "test classes are fun"; + Node testNode("a#test.test.classes.are.fun"); + // get the test node's classlist. + const auto classList = testNode.GetAttribute("class"); + bool test = assert_strings_equal(classString, classList); + std::cout << "Class Test " << ((test) ? "passed!" : "failed!") << std::endl << + "Class Output: " << classList << std::endl << + // use a double end line at the end for spacing between tests + "Expected Output: " << classString << std::endl << std::endl; +} + +// this test checks if the attributes provided are correctly stored and gotten +void run_attribute_test() { + const auto attrOutput = "testAttr1"; + const auto attr2Output = "testAttr2"; + const auto attr3Output = ""; + Node testNode("a"); + // set two attributes on the node + testNode.SetAttribute("attr1", "testAttr1").SetAttribute("attr2", "testAttr2"); + // get each attribute's output + const auto attrOut = testNode.GetAttribute("attr1"); + const auto attr2Out = testNode.GetAttribute("attr2"); + const auto attr3Out = testNode.GetAttribute("attr3"); + // test each string + auto test1 = assert_strings_equal(attrOutput, attrOut); + auto test2 = assert_strings_equal(attr2Output, attr2Out); + auto test3 = assert_strings_equal(attr3Output, attr3Out); + std::cout << "Class Test " << ((test1 && test2 && test3) ? "passed!" : "failed!") << std::endl << + "Attr 1 Output: " << attrOut << std::endl << + "Expected Output: " << attrOutput << std::endl << + "Attr 2 Output: " << attr2Out << std::endl << + "Expected Output: " << attr2Output << std::endl << + "Attr 3 Output: " << attr3Out << std::endl << + // use a double end line at the end for spacing between tests + "Expected Output: " << attr3Output << std::endl << std::endl; + +} + +int main() { + high_res_clock::time_point begin = high_res_clock::now(); + run_escape_test(); + run_document_test(); + run_class_test(); + run_attribute_test(); + high_res_clock::time_point end = high_res_clock::now(); + millis ms = std::chrono::duration_cast(end - begin); + std::cout << "Tests ran in " << ms.count() << "ms" << std::endl; + return 0; +} \ No newline at end of file