diff --git a/dist/api/blog/blogData.php b/dist/api/blog/blogData.php index 95dd912..a8f8c6f 100644 --- a/dist/api/blog/blogData.php +++ b/dist/api/blog/blogData.php @@ -444,22 +444,87 @@ class blogData if ($result) { - $bodyText = array_column($result, "bodyText"); - // go through each body plain text and get the sentence before, the sentence with the search term and the sentence after and append it to a new array - foreach ($bodyText as $key => $text) + for ($i = 0; $i < count($result); $i++) { - $text = strtolower($text); - $searchTerm = strtolower($searchTerm); - $pos = strpos($text, $searchTerm); - $start = strrpos(substr($text, 0, $pos), ".") + 1; - $end = strpos($text, ".", $pos); - $result[$key]["bodyText"] = substr($text, $start, $end - $start); + $result[$i]["abstract"] = $this->getShortPost($searchTerm, stripcslashes($result[$i]["bodyText"])); } - return $result; } return array("errorMessage" => "Error, could not find posts"); } + + /** + * Get the short post with the search term + * @param string $searchTerm - Search term + * @param $text - Body of the post as plain text + * @return string - Short post with the search term + */ + private function getShortPost(string $searchTerm, $text): string + { + $pattern = '/([,:;!?.-]+)/u'; + $parts = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + + $cleanedParts = []; + + foreach ($parts as $part) + { + $part = trim($part); // Remove leading/trailing spaces and newline characters + if (!empty($part)) + { + $cleanedParts[] = $part; + } + } + + $combinedParts = []; + $currentPart = ''; + + foreach ($cleanedParts as $part) + { + if (preg_match('/[,:;!?.-]/u', $part)) + { + $currentPart .= $part; + } + else + { + if (!empty($currentPart)) + { + $combinedParts[] = trim($currentPart); + } + $currentPart = rtrim($part); + } + } + + if (!empty($currentPart)) + { + $combinedParts[] = trim($currentPart); + } + + $result = ""; + + + for ($i = 0; $i < count($combinedParts); $i++) + { + $part = $combinedParts[$i]; + + if (stripos($part, $searchTerm) !== false) + { + $before = ($i > 0) ? $combinedParts[$i - 1] : ""; + $after = ($i < count($combinedParts) - 1) ? $combinedParts[$i + 1] : ""; + + if ($before === "" && $i > 0) + { + $before = $combinedParts[$i - 1]; + } + + $result = $before . " " . $part . " " . $after; + + // If the search term is found, we don't need to continue checking subsequent parts + break; + } + } + + return $result; + } } \ No newline at end of file diff --git a/dist/api/blog/blogRoutes.php b/dist/api/blog/blogRoutes.php index 7a7933a..d3c4201 100644 --- a/dist/api/blog/blogRoutes.php +++ b/dist/api/blog/blogRoutes.php @@ -254,7 +254,7 @@ class blogRoutes implements routesInterface } $featured = $data["featured"] === "true"; - $insertedID = $this->blogData->createPost($data["title"], $data["abstract"], $data["body"], $data["dateCreated"], $featured, $data["categories"], $headerImg); + $insertedID = $this->blogData->createPost($data["title"], $data["abstract"], $data["body"], $data["bodyText"], $data["dateCreated"], $featured, $data["categories"], $headerImg); if (!is_int($insertedID)) { // uh oh something went wrong diff --git a/dist/blog/index.html b/dist/blog/index.html index e67e83f..471db0e 100644 --- a/dist/blog/index.html +++ b/dist/blog/index.html @@ -1 +1 @@ -Rohit Pai - Blog

full stack developer

Contact Me
\ No newline at end of file +Rohit Pai - Blog

full stack developer

Contact Me
\ No newline at end of file diff --git a/dist/blog/js/index.js b/dist/blog/js/index.js index be84bfc..dc5f439 100644 --- a/dist/blog/js/index.js +++ b/dist/blog/js/index.js @@ -1 +1 @@ -const scrollLimit=150;function goToURL(e){let t=e.split("/");if("/blog/"!==e&&"/blog"!==e){if("post"!==t[2])return"category"===t[2]?t[3]?void loadPostsByCategory(t[t.length-1]):void loadAllCategories():void show404();loadIndividualPost(t[t.length-1]).catch((e=>console.log(e)))}else loadHomeContent()}function createLargePost(e){let t=document.createElement("div");t.classList.add("outerContent");let n=document.createElement("img");n.className="banner",n.src=e.headerImg,n.alt=e.title,t.appendChild(n);let a=document.createElement("div");a.classList.add("content");let o=document.createElement("div");o.classList.add("postContent");let s="";return e.categories.split(", ").forEach((t=>{s+=`${t}`,e.categories.split(", ").length>1&&(s+=", ")})),s.endsWith(", ")&&(s=s.substring(0,s.length-2)),o.innerHTML=`\n

${e.title}

\n

Last updated: ${e.dateModified} | ${s}

\n

${e.abstract}

\n See Post\n `,a.appendChild(o),t.appendChild(a),t}function loadHomeContent(){let e=document.createElement("div");e.classList.add("menuBar"),e.innerHTML='\n \n\t',document.querySelector("#main").appendChild(e),fetch("/api/blog/post").then((e=>e.json().then((e=>{for(let t=0;te.json())),await fetch("/api/blog/post/featured").then((e=>e.json()))]}function csvToArray(e){let t="",n=[""],a=0,o=!0,s=null;for(s of e)'"'===s?(o&&s===t&&(n[a]+=s),o=!o):","===s&&o?s=n[++a]="":"\n"===s&&o?("\r"===t&&(row[a]=row[a].slice(0,-1)),n=n[++r]=[s=""],a=0):n[a]+=s,t=s;return n}async function getCategories(){let e=await fetch("/api/blog/categories").then((e=>e.json())),t=[];return e.forEach((e=>t=t.concat(csvToArray(e.categories.replace(/\s*,\s*/g,","))))),[...new Set(t)]}function createCategories(e){let t="";return e.forEach((e=>t+=`${e}`)),t}function createButtonCategories(e){let t="";return e.forEach((e=>e.forEach((e=>t+=`${e}`)))),t}async function createSideContent(){let e=await getLatestAndFeaturedPosts(),t=e[0],n=e[1],a=createCategories(await getCategories()),o=document.createElement("aside");return o.classList.add("sideContent"),o.innerHTML=`\n
\n
\n My professional picture taken in brighton near \n                                        north street at night wearing a beige jacket and checkered shirt\n

Rohit Pai

\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n

Avid Full Stack Dev | Uni of Notts Grad | Amateur Blogger

\n\n
\n \n \n
\n

categories

\n ${a}\n
\n `,o}async function loadIndividualPost(e){document.title="Rohit Pai - "+decodeURI(e),await fetch(`/api/blog/post/${e}`).then((async e=>{e.ok?await e.json().then((async e=>{let t=document.createElement("section");t.classList.add("post"),t.id="individualPost";let n=document.createElement("div");n.classList.add("mainContent");let a=document.createElement("article");a.innerHTML=`\n

${e.title}

\n
\n

Last updated: ${e.dateModified}

\n

${createButtonCategories([csvToArray(e.categories.replace(/\s*,\s*/g,","))])}

\n
\n
\n ${e.body}\n `;let o=document.createElement("section");o.classList.add("comments"),o.innerHTML='

Comments

\n
\n ',n.appendChild(a),n.appendChild(o);let s=await createSideContent();t.appendChild(n),t.appendChild(s),document.querySelector("#main").appendChild(t);var c,i;c=document,(i=c.createElement("script")).src="https://rohitpaiportfolio.disqus.com/embed.js",i.setAttribute("data-timestamp",+new Date),c.body.appendChild(i)})):show404()}))}async function loadAllCategories(){document.title="Rohit Pai - Categories";let e=await getCategories(),t=document.querySelector("#main"),n=document.createElement("section");n.classList.add("categories"),n.id="allCategories";let a=document.createElement("h1");a.innerHTML="Categories",t.appendChild(a);for(let t of e){let e=document.createElement("div");e.classList.add("btnContainer");let a=document.createElement("a");a.classList.add("btn"),a.classList.add("btnPrimary"),a.innerHTML=t,a.href=`/blog/category/${t}`,e.appendChild(a),n.appendChild(e)}t.appendChild(n)}function loadPostsByCategory(e){document.title="Rohit Pai - "+decodeURI(e),fetch(`/api/blog/categories/${e}`).then((t=>t.json().then((t=>{let n=document.querySelector("#main"),a=document.createElement("section");a.classList.add("catPosts"),a.id="postsByCategory";let o=document.createElement("h1");o.innerHTML=decodeURI(e),n.appendChild(o);for(let e=0;e{goToURL(window.location.pathname)})),window.addEventListener("popstate",(e=>{goToURL(window.history.state)})),window.onscroll=()=>{document.body.scrollTop>=150||document.documentElement.scrollTop>=150?document.querySelector("nav").classList.add("scrolled"):document.querySelector("nav").classList.remove("scrolled")}; \ No newline at end of file +const scrollLimit=150;function goToURL(e){let t=e.split("/");if("/blog/"!==e&&"/blog"!==e){if("post"!==t[2])return"category"===t[2]?t[3]?void loadPostsByCategory(t[t.length-1]):void loadAllCategories().catch((e=>console.log(e))):void("search"===t[2]&&t[3]?loadSearchResults(t[t.length-1]):show404());loadIndividualPost(t[t.length-1]).catch((e=>console.log(e)))}else loadHomeContent()}function createLargePost(e){let t=document.createElement("div");t.classList.add("outerContent");let n=document.createElement("img");n.className="banner",n.src=e.headerImg,n.alt=e.title,t.appendChild(n);let a=document.createElement("div");a.classList.add("content");let o=document.createElement("div");o.classList.add("postContent");let s="";return e.categories.split(", ").forEach((t=>{s+=`${t}`,e.categories.split(", ").length>1&&(s+=", ")})),s.endsWith(", ")&&(s=s.substring(0,s.length-2)),o.innerHTML=`\n

${e.title}

\n

Last updated: ${e.dateModified} | ${s}

\n

${e.abstract}

\n See Post\n `,a.appendChild(o),t.appendChild(a),t}function loadHomeContent(){fetch("/api/blog/post").then((e=>e.json().then((e=>{for(let t=0;te.json())),await fetch("/api/blog/post/featured").then((e=>e.json()))]}function csvToArray(e){let t="",n=[""],a=0,o=!0,s=null;for(s of e)'"'===s?(o&&s===t&&(n[a]+=s),o=!o):","===s&&o?s=n[++a]="":"\n"===s&&o?("\r"===t&&(row[a]=row[a].slice(0,-1)),n=n[++r]=[s=""],a=0):n[a]+=s,t=s;return n}async function getCategories(){let e=await fetch("/api/blog/categories").then((e=>e.json())),t=[];return e.forEach((e=>t=t.concat(csvToArray(e.categories.replace(/\s*,\s*/g,","))))),[...new Set(t)]}function createCategories(e){let t="";return e.forEach((e=>t+=`${e}`)),t}function createButtonCategories(e){let t="";return e.forEach((e=>e.forEach((e=>t+=`${e}`)))),t}async function createSideContent(){let e=await getLatestAndFeaturedPosts(),t=e[0],n=e[1],a=createCategories(await getCategories()),o=document.createElement("aside");return o.classList.add("sideContent"),o.innerHTML=`\n
\n
\n My professional picture taken in brighton near \n                                        north street at night wearing a beige jacket and checkered shirt\n

Rohit Pai

\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n

Avid Full Stack Dev | Uni of Notts Grad | Amateur Blogger

\n\n
\n \n \n
\n

categories

\n ${a}\n
\n `,o}async function loadIndividualPost(e){document.title="Rohit Pai - "+decodeURI(e),await fetch(`/api/blog/post/${e}`).then((async e=>{e.ok?await e.json().then((async e=>{let t=document.createElement("section");t.classList.add("post"),t.id="individualPost";let n=document.createElement("div");n.classList.add("mainContent");let a=document.createElement("article");a.innerHTML=`\n

${e.title}

\n \n
\n ${e.body}\n `;let o=document.createElement("section");o.classList.add("comments"),o.innerHTML='

Comments

\n
\n ',n.appendChild(a),n.appendChild(o);let s=await createSideContent();t.appendChild(n),t.appendChild(s),document.querySelector("#main").appendChild(t);var c,l;c=document,(l=c.createElement("script")).src="https://rohitpaiportfolio.disqus.com/embed.js",l.setAttribute("data-timestamp",+new Date),c.body.appendChild(l)})):show404()}))}async function loadAllCategories(){document.title="Rohit Pai - Categories";let e=await getCategories(),t=document.querySelector("#main"),n=document.createElement("section");n.classList.add("categories"),n.id="allCategories";let a=document.createElement("h1");a.innerHTML="Categories",t.appendChild(a);for(let t of e){let e=document.createElement("div");e.classList.add("btnContainer");let a=document.createElement("a");a.classList.add("btn"),a.classList.add("btnPrimary"),a.innerHTML=t,a.href=`/blog/category/${t}`,e.appendChild(a),n.appendChild(e)}t.appendChild(n)}function loadPostsByCategory(e){document.title="Rohit Pai - "+decodeURI(e),fetch(`/api/blog/categories/${e}`).then((t=>t.json().then((t=>{let n=document.querySelector("#main"),a=document.createElement("section");a.classList.add("catPosts"),a.id="postsByCategory";let o=document.createElement("h1");o.innerHTML=decodeURI(e),n.appendChild(o);for(let e=0;ee.json().then((e=>{let t=document.querySelector("#main"),n=document.createElement("section");n.classList.add("catPosts"),n.id="searchResults";let a=document.createElement("h1");a.innerHTML="Search Results",t.appendChild(a);for(let t=0;t{goToURL(window.location.pathname)})),window.addEventListener("popstate",(e=>{goToURL(window.history.state)})),window.onscroll=()=>{document.body.scrollTop>=150||document.documentElement.scrollTop>=150?document.querySelector("nav").classList.add("scrolled"):document.querySelector("nav").classList.remove("scrolled")},document.querySelector("#searchBtn").addEventListener("click",(e=>{let t=document.querySelector("#searchField").value;t.length>0&&(window.history.pushState(null,null,`/blog/search/${t}`),document.querySelector("#searchField").value="",document.querySelector("#main").innerHTML="",goToURL(`/blog/search/${t}`))})),document.querySelector("#searchField").addEventListener("keyup",(e=>{"Enter"===e.key&&document.querySelector("#searchBtn").click()})); \ No newline at end of file diff --git a/dist/editor/editor.html b/dist/editor/editor.html index 4b91781..89aea41 100644 --- a/dist/editor/editor.html +++ b/dist/editor/editor.html @@ -1 +1 @@ -Editor

Editor

curriculum vitae

Education

Work

projects

add post

edit post

TitleDate CreatedDate ModifiedAction
\ No newline at end of file +Editor

Editor

curriculum vitae

Education

Work

projects

add post

edit post

TitleDate CreatedDate ModifiedAction
\ No newline at end of file diff --git a/dist/editor/js/editor.js b/dist/editor/js/editor.js index 912e97d..a88e6e3 100644 --- a/dist/editor/js/editor.js +++ b/dist/editor/js/editor.js @@ -1 +1 @@ -let dateOptions={month:"short",year:"numeric"},textareaLoaded=!1,editors={},posts=null;const smallPaddingElements=["figcaption","li"];function goToPage(e){document.querySelectorAll(".editor section").forEach((t=>{t.style.display="none",t.id===e&&(t.style.display="flex")}))}function viewToPlainText(e){let t="";if(e.is("$text")||e.is("$textProxy"))t=e.data;else if(e.is("element","img")&&e.hasAttribute("alt"))t=e.getAttribute("alt");else if(e.is("element","br"))t="\n";else{let a=null;for(const l of e.getChildren()){const e=viewToPlainText(l);a&&(a.is("containerElement")||l.is("containerElement"))&&(smallPaddingElements.includes(a.name)||smallPaddingElements.includes(l.name)?t+="\n":t+="\n\n"),t+=e,a=l}}return t}function addActiveClass(e){document.querySelectorAll("nav.sideNav ul li a").forEach((t=>{t.classList.remove("active"),t.id===e&&t.classList.add("active")}))}function editProjectItem(e){document.querySelector(`#projectItem${e}`).classList.toggle("editing"),document.querySelector(`#title${e}proj`).toggleAttribute("disabled"),document.querySelector(`#info${e}proj`).toggleAttribute("disabled")}function createEditors(...e){e.forEach((e=>{ClassicEditor.create(document.querySelector(`#${e}`),{placeholder:"Write something amazing...",simpleUpload:{uploadUrl:"/api/blog/uploadPostImage",headers:{Authorization:"Bearer "+localStorage.getItem("token")}},style:{definitions:[{name:"Button Primary",element:"a",classes:["btn","btnPrimary"]},{name:"Button Primary",element:"button",classes:["btn","btnPrimary"]}]},codeBlock:{languages:[{language:"plaintext",label:"Plain text"},{language:"abap",label:"ABAP"},{language:"abnf",label:"ABNF"},{language:"actionscript",label:"ActionScript"},{language:"ada",label:"Ada"},{language:"agda",label:"Agda"},{language:"al",label:"AL"},{language:"antlr4",label:"ANTLR4"},{language:"apacheconf",label:"Apache Configuration"},{language:"apex",label:"Apex"},{language:"apl",label:"APL"},{language:"applescript",label:"AppleScript"},{language:"aql",label:"AQL"},{language:"arduino",label:"Arduino"},{language:"arff",label:"ARFF"},{language:"asciidoc",label:"AsciiDoc"},{language:"aspnet",label:"ASP.NET (C#)"},{language:"asm6502",label:"6502 Assembly"},{language:"autohotkey",label:"AutoHotkey"},{language:"autoit",label:"AutoIt"},{language:"bash",label:"Bash"},{language:"basic",label:"BASIC"},{language:"batch",label:"Batch"},{language:"bbcode",label:"BBcode"},{language:"bison",label:"Bison"},{language:"bnf",label:"BNF"},{language:"brainfuck",label:"Brainfuck"},{language:"brightscript",label:"BrightScript"},{language:"bro",label:"Bro"},{language:"c",label:"C"},{language:"concurnas",label:"Concurnas"},{language:"csharp",label:"C#"},{language:"cpp",label:"C++"},{language:"cil",label:"CIL"},{language:"clojure",label:"Clojure"},{language:"cmake",label:"CMake"},{language:"coffeescript",label:"CoffeeScript"},{language:"concurnas",label:"Concurnas"},{language:"crystal",label:"Crystal"},{language:"css-extras",label:"CSS Extras"},{language:"css",label:"CSS"},{language:"d",label:"D"},{language:"dart",label:"Dart"},{language:"dax",label:"DAX"},{language:"dhall",label:"Dhall"},{language:"diff",label:"Diff"},{language:"django",label:"Django/Jinja2"},{language:"dns-zone-file",label:"DNS zone file"},{language:"docker",label:"Docker"},{language:"ebnf",label:"EBNF"},{language:"editorconfig",label:"EditorConfig"},{language:"eiffel",label:"Eiffel"},{language:"ejs",label:"EJS"},{language:"elixir",label:"Elixir"},{language:"elm",label:"Elm"},{language:"etlua",label:"Embedded Lua"},{language:"erb",label:"ERB"},{language:"erlang",label:"Erlang"},{language:"excel-formula",label:"Excel Formula"},{language:"fsharp",label:"F#"},{language:"factor",label:"Factor"},{language:"firestore-security-rules",label:"Firestore security rules"},{language:"flow",label:"Flow"},{language:"fortran",label:"Fortran"},{language:"ftl",label:"FreeMarker Template Language"},{language:"gcode",label:"G-code"},{language:"gdscript",label:"GDScript"},{language:"gedcom",label:"GEDCOM"},{language:"gherkin",label:"Gherkin"},{language:"git",label:"Git"},{language:"glsl",label:"GLSL"},{language:"gml",label:"GameMaker Language"},{language:"go",label:"Go"},{language:"graphql",label:"GraphQL"},{language:"groovy",label:"Groovy"},{language:"haml",label:"Haml"},{language:"handlebars",label:"Handlebars"},{language:"haskell",label:"Haskell"},{language:"haxe",label:"Haxe"},{language:"hcl",label:"HCL"},{language:"hlsl",label:"HLSL"},{language:"http",label:"HTTP"},{language:"hpkp",label:"HTTP Public-Key-Pins"},{language:"hsts",label:"HTTP Strict-Transport-Security"},{language:"ichigojam",label:"IchigoJam"},{language:"icon",label:"Icon"},{language:"ignore",label:"Ignore"},{language:"inform7",label:"Inform 7"},{language:"ini",label:"Ini"},{language:"io",label:"Io"},{language:"j",label:"J"},{language:"java",label:"Java"},{language:"javadoc",label:"JavaDoc"},{language:"javadoclike",label:"JavaDoc-like"},{language:"javascript",label:"JavaScript"},{language:"javastacktrace",label:"Java stack trace"},{language:"jolie",label:"Jolie"},{language:"jq",label:"JQ"},{language:"js-extras",label:"JS Extras"},{language:"js-templates",label:"JS Templates"},{language:"jsdoc",label:"JSDoc"},{language:"json",label:"JSON"},{language:"json5",label:"JSON5"},{language:"jsonp",label:"JSONP"},{language:"jsstacktrace",label:"JS stack trace"},{language:"jsx",label:"React JSX"},{language:"julia",label:"Julia"},{language:"keyman",label:"Keyman"},{language:"kotlin",label:"Kotlin"},{language:"latex",label:"LaTeX"},{language:"latte",label:"Latte"},{language:"less",label:"Less"},{language:"lilypond",label:"LilyPond"},{language:"liquid",label:"Liquid"},{language:"lisp",label:"Lisp"},{language:"livescript",label:"LiveScript"},{language:"llvm",label:"LLVM IR"},{language:"log",label:"Log file"},{language:"lolcode",label:"LOLCODE"},{language:"lua",label:"Lua"},{language:"makefile",label:"Makefile"},{language:"markdown",label:"Markdown"},{language:"markup-templating",label:"Markup templating"},{language:"matlab",label:"MATLAB"},{language:"mel",label:"MEL"},{language:"mizar",label:"Mizar"},{language:"mongodb",label:"MongoDB"},{language:"monkey",label:"Monkey"},{language:"moonscript",label:"MoonScript"},{language:"n1ql",label:"N1QL"},{language:"n4js",label:"N4JS"},{language:"nand2tetris-hdl",label:"Nand To Tetris HDL"},{language:"nasm",label:"NASM"},{language:"neon",label:"NEON"},{language:"nginx",label:"nginx"},{language:"nim",label:"Nim"},{language:"nix",label:"Nix"},{language:"nsis",label:"NSIS"},{language:"objectivec",label:"Objective-C"},{language:"ocaml",label:"OCaml"},{language:"opencl",label:"OpenCL"},{language:"oz",label:"Oz"},{language:"parigp",label:"PARI/GP"},{language:"parser",label:"Parser"},{language:"pascal",label:"Pascal"},{language:"pascaligo",label:"Pascaligo"},{language:"pcaxis",label:"PC-Axis"},{language:"peoplecode",label:"PeopleCode"},{language:"perl",label:"Perl"},{language:"php",label:"PHP"},{language:"phpdoc",label:"PHPDoc"},{language:"php-extras",label:"PHP Extras"},{language:"plsql",label:"PL/SQL"},{language:"powerquery",label:"PowerQuery"},{language:"powershell",label:"PowerShell"},{language:"processing",label:"Processing"},{language:"prolog",label:"Prolog"},{language:"properties",label:".properties"},{language:"protobuf",label:"Protocol Buffers"},{language:"pug",label:"Pug"},{language:"puppet",label:"Puppet"},{language:"pure",label:"Pure"},{language:"purebasic",label:"PureBasic"},{language:"python",label:"Python"},{language:"q",label:"Q (kdb+ database)"},{language:"qml",label:"QML"},{language:"qore",label:"Qore"},{language:"r",label:"R"},{language:"racket",label:"Racket"},{language:"jsx",label:"React JSX"},{language:"tsx",label:"React TSX"},{language:"reason",label:"Reason"},{language:"regex",label:"Regex"},{language:"renpy",label:"Ren'py"},{language:"rest",label:"reST (reStructuredText)"},{language:"rip",label:"Rip"},{language:"roboconf",label:"Roboconf"},{language:"robotframework",label:"Robot Framework"},{language:"ruby",label:"Ruby"},{language:"rust",label:"Rust"},{language:"sas",label:"SAS"},{language:"sass",label:"Sass (Sass)"},{language:"scss",label:"Sass (Scss)"},{language:"scala",label:"Scala"},{language:"scheme",label:"Scheme"},{language:"shell-session",label:"Shell session"},{language:"smali",label:"Smali"},{language:"smalltalk",label:"Smalltalk"},{language:"smarty",label:"Smarty"},{language:"solidity",label:"Solidity (Ethereum)"},{language:"solution-file",label:"Solution file"},{language:"soy",label:"Soy (Closure Template)"},{language:"sparql",label:"SPARQL"},{language:"splunk-spl",label:"Splunk SPL"},{language:"sqf",label:"SQF: Status Quo Function (Arma 3)"},{language:"sql",label:"SQL"},{language:"stan",label:"Stan"},{language:"stata",label:"Stata"},{language:"step21",label:"STEP Part 21"},{language:"stylus",label:"Stylus"},{language:"swift",label:"Swift"},{language:"tap",label:"TAP"},{language:"tcl",label:"Tcl"},{language:"textile",label:"Textile"},{language:"toml",label:"TOML"},{language:"tt2",label:"Template Toolkit 2"},{language:"turtle",label:"Turtle"},{language:"twig",label:"Twig"},{language:"typescript",label:"TypeScript"},{language:"t4-cs",label:"T4 Text Templates (C#)"},{language:"t4-vb",label:"T4 Text Templates (VB)"},{language:"t4-templating",label:"T4 templating"},{language:"unrealscript",label:"UnrealScript"},{language:"vala",label:"Vala"},{language:"vbnet",label:"VB.Net"},{language:"velocity",label:"Velocity"},{language:"verilog",label:"Verilog"},{language:"vhdl",label:"VHDL"},{language:"vim",label:"vim"},{language:"visual-basic",label:"Visual Basic"},{language:"warpscript",label:"WarpScript"},{language:"wasm",label:"WebAssembly"},{language:"wiki",label:"Wiki markup"},{language:"xeora",label:"Xeora"},{language:"xojo",label:"Xojo (REALbasic)"},{language:"xquery",label:"XQuery"},{language:"yaml",label:"YAML"},{language:"zephir",label:"Zephir"}]}}).then((t=>{editors[e]=t})).catch((e=>{console.error("Oops, something went wrong!"),console.error("Please, report the following error on https://github.com/ckeditor/ckeditor5/issues with the build id and the error stack trace:"),console.warn("Build id: 1eo8ioyje2om-vgar4aghypdm"),console.error(e)}))}))}function editPostItem(e){posts.forEach((t=>{t.ID===e&&(document.querySelector("#editPostTitle").value=t.title,document.querySelector("#editIsFeatured").checked=1===t.featured,document.querySelector("#editPostCategories").value=t.categories,document.querySelector("#editPostAbstract").value=t.abstract,editors.CKEditorEditPost.setData(t.body),document.querySelector("#editPostForm input[type='submit']").id=e)}))}function showErrorMessage(e,t){document.querySelector(`#${t}Error`).classList.remove("hidden"),document.querySelector(`#${t}Error div`).innerText=e}function showSuccessMessage(e,t){document.querySelector(`#${t}Success`).classList.remove("hidden"),document.querySelector(`#${t}Success div`).innerText=e}function editCVItem(e){if(textareaLoaded=!1,document.querySelector(`#timelineItem${e}`).classList.toggle("editing"),e.includes("e"))return document.querySelector(`#grade${e}`).toggleAttribute("disabled"),void document.querySelector(`#course${e}`).toggleAttribute("disabled");document.querySelector(`#companyName${e}`).toggleAttribute("disabled"),document.querySelector(`#area${e}`).toggleAttribute("disabled"),document.querySelector(`#jobTitle${e}`).toggleAttribute("disabled")}function addEduData(e,t,a,l,o,n=!1){let r=e+"e",i=document.createElement("form");i.id="timelineItem"+r,i.classList.add("timelineItem"),i.onsubmit=t=>updateEduItem(e,t),i.innerHTML=`\n
\n \n \n
\n
\n \n -\n \n
\n

${new Date(t).toLocaleString("en-gb",dateOptions)} - ${new Date(a).toLocaleString("en-gb",dateOptions)}

\n
\n \n \n
\n
\n \n
\n \n \n \n `,n?document.querySelector("#edu").prepend(i):document.getElementById("edu").appendChild(i)}function addWorkData(e,t,a,l,o,n,r=!1){let i=e+"w",d=document.createElement("form");d.id="timelineItem"+i,d.classList.add("timelineItem"),d.onsubmit=t=>updateWorkItem(e,t),d.innerHTML=`\n
\n \n \n
\n
\n \n -\n \n
\n

${new Date(t).toLocaleString("en-gb",dateOptions)} - ${"Present"===a?"Present":new Date(a).toLocaleString("en-gb",dateOptions)}

\n
\n \n -\n \n
\n
\n \n
\n \n \n \n\t`,r?document.querySelector("#work").prepend(d):document.getElementById("work").appendChild(d)}function updateEduItem(e,t){t.preventDefault();let a={};a.dateFrom=document.querySelector(`#dateFrom${e}e`).value,a.dateTo=document.querySelector(`#dateTo${e}e`).value,a.grade=document.querySelector(`#grade${e}e`).value,a.course=document.querySelector(`#course${e}e`).value,fetch("/api/timelineData/edu/"+e,{method:"PATCH",body:JSON.stringify(a),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return document.querySelector(`#timelineHeader${e}e`).innerHTML=new Date(document.querySelector(`#dateFrom${e}e`).value).toLocaleString("en-gb",dateOptions)+" - "+new Date(document.querySelector(`#dateTo${e}e`).value).toLocaleString("en-gb",dateOptions),document.querySelector(`#timelineItem${e}e`).classList.toggle("editing"),document.querySelector(`#grade${e}e`).setAttribute("disabled",""),void document.querySelector(`#course${e}e`).setAttribute("disabled","");401!==t.status?t.json().then((t=>{document.querySelector(`#eduError${e}e`).classList.remove("hidden"),document.querySelector(`#eduError${e}e div`).innerHTML=t.error})):window.location.href="./"}))}function updateWorkItem(e,t){t.preventDefault();let a={};a.dateFrom=document.querySelector(`#dateFrom${e}w`).value,a.dateTo=document.querySelector(`#dateTo${e}w`).value,a.companyName=document.querySelector(`#companyName${e}w`).value,a.area=document.querySelector(`#area${e}w`).value,a.title=document.querySelector(`#jobTitle${e}w`).value,fetch("/api/timelineData/work/"+e,{method:"PATCH",body:JSON.stringify(a),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return document.querySelector(`#timelineHeader${e}w`).innerHTML=new Date(document.querySelector(`#dateFrom${e}w`).value).toLocaleString("en-gb",dateOptions)+" - "+new Date(document.querySelector(`#dateTo${e}w`).value).toLocaleString("en-gb",dateOptions),document.querySelector(`#timelineItem${e}w`).classList.toggle("editing"),document.querySelector(`#companyName${e}w`).setAttribute("disabled",""),document.querySelector(`#area${e}w`).setAttribute("disabled",""),void document.querySelector(`#jobTitle${e}w`).setAttribute("disabled","");401!==t.status?t.json().then((t=>{document.querySelector(`#workError${e}w`).classList.remove("hidden"),document.querySelector(`#workError${e}w div`).innerHTML=t.error})):window.location.href="./"}))}function deleteEduItem(e){fetch("/api/timelineData/edu/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#timelineItem${e}e`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}function deleteWorkItem(e){fetch("/api/timelineData/work/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#timelineItem${e}w`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}function updateProjectItem(e,t){t.preventDefault();let a={};a.title=document.querySelector(`#title${e}`).value,a.isMainProject=document.querySelector(`#isMainProject${e}`).checked?"true":"false",a.information=document.querySelector(`#info${e}`).value,a.projectLink=document.querySelector(`#viewProj${e}`).value,a.gitLink=document.querySelector(`#git${e}`).value;let l=new FormData;l.append("img",document.querySelector(`#img${e}`).files[0]),fetch("/api/projectData/"+e,{method:"PATCH",body:JSON.stringify(a),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return"undefined"===l.get("img")?("true"===a.isMainProject&&(document.querySelectorAll(".isMainProject input").forEach((e=>e.checked=!1)),document.querySelector(`#isMainProject${e}`).checked=!0,document.querySelector("#projList").prepend(document.querySelector(`#projectItem${e}`))),document.querySelector(`#projectItem${e}`).classList.toggle("editing"),document.querySelector(`#title${e}`).setAttribute("disabled",""),void document.querySelector(`#info${e}`).setAttribute("disabled","")):(console.log("updating image"),fetch("/api/projectImage/"+e,{method:"POST",body:l,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}));401!==t.status?t.json().then((t=>{document.querySelector(`#projError${e}`).classList.remove("hidden"),document.querySelector(`#projError${e} div`).innerHTML=t.error})):window.location.href="./"})).then((t=>t.json().then((a=>{if(t.ok)return"true"===a.isMainProject&&(document.querySelectorAll(".isMainProject input").forEach((e=>e.checked=!1)),document.querySelector(`#isMainProject${e}`).checked=!0,document.querySelector("#projList").prepend(document.querySelector(`#projectItem${e}`))),document.querySelector(`#projectItem${e}`).classList.toggle("editing"),document.querySelector(`#title${e}`).setAttribute("disabled",""),document.querySelector(`#info${e}`).setAttribute("disabled",""),void(document.querySelector(`#projectImage${e}`).src=a.imgLocation);401!==t.status?(document.querySelector(`#projError${e}`).classList.remove("hidden"),document.querySelector(`#projError${e} div`).innerHTML=a.error):window.location.href="./"}))))}function deleteProjectItem(e){fetch("/api/projectData/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#projectItem${e}`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}function addProject(e,t,a,l,o,n,r){let i=document.createElement("form"),d=e+"proj";if(i.id="projectItem"+e,i.classList.add("projItem"),i.onsubmit=t=>updateProjectItem(e,t),i.innerHTML=`\n
\n \n \n
\n image preivew of the project\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n \n \n \n `,"true"===t)return document.querySelectorAll(".isMainProject input").forEach((e=>e.checked=!1)),void document.querySelector("#projList").prepend(i);document.querySelector("#projList").appendChild(i)}function deletePostItem(e){fetch("/api/blog/post/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#postInfo${e}`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}function addPostInfo(e,t,a,l){let o=document.createElement("tr"),n=e+"post";o.id="postInfo"+e,o.innerHTML=`\n \n ${t}\n \n \n ${new Date(a).toLocaleDateString()}\n \n \n ${new Date(l).toLocaleDateString()}\n \n \n \n \n \n `,document.querySelector("#editPost table tbody").appendChild(o)}document.addEventListener("DOMContentLoaded",(()=>{fetch("/api/user/isLoggedIn").then((e=>{e.ok||(window.location.href="./")})),document.querySelector("#dateFromE").max=(new Date).toISOString().split("T")[0],document.querySelector("#dateFromW").max=(new Date).toISOString().split("T")[0],fetch("/api/timelineData/edu").then((e=>e.json().then((t=>{if(e.ok)for(let e=0;ee.json().then((t=>{if(e.ok)for(let e=0;ee.json().then((t=>{e.ok?t.forEach((e=>{addProject(e.ID,1===e.isMainProject?"true":"false",""===e.imgLocation?"../imgs/placeholder.png":e.imgLocation,e.title,e.information,e.projectLink,e.gitLink)})):document.querySelector("#projList").innerHTML="No project data found"})))),fetch("/api/blog/post").then((e=>e.json().then((t=>{e.ok&&(posts=t,t.forEach((e=>{addPostInfo(e.ID,e.title,e.dateCreated,e.dateModified)})))})))),createEditors("CKEditorAddPost","CKEditorEditPost")})),document.querySelector("body").addEventListener("click",(()=>{if(textareaLoaded)return;const e=document.querySelectorAll("main.editor textarea");for(let t=0;t{e.target.style.height="0",e.target.style.height=e.target.scrollHeight+15+"px"};textareaLoaded=!0})),document.querySelector("#navOpen").addEventListener("click",(e=>{document.querySelector("nav.sideNav").style.removeProperty("width"),document.querySelector("main.editor").style.removeProperty("margin-left"),e.target.style.removeProperty("visibility")})),document.querySelector("#navClose").addEventListener("click",(()=>{document.querySelector("nav.sideNav").style.width="0",document.querySelector("main.editor").style.marginLeft="0",document.querySelector("#navOpen").style.visibility="visible"})),document.querySelector("#addEdu").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;t.append("dateFrom",document.querySelector("#dateFromE").value),t.append("dateTo",document.querySelector("#dateToE").value),t.append("grade",document.querySelector("#grade").value),t.append("course",document.querySelector("#courseTitle").value),fetch("/api/timelineData/edu",{method:"POST",body:t,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>e.json().then((a=>{if(e.ok)return addEduData(a.ID,t.get("dateFrom"),t.get("dateTo"),t.get("grade"),t.get("course"),!0),void document.querySelector("#addEdu").reset();401!==e.status?showErrorMessage(a.error,"edu"):window.location.href="./"}))))})),document.querySelector("#addWork").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;t.append("dateFrom",document.querySelector("#dateFromW").value),t.append("dateTo",document.querySelector("#dateToW").value),t.append("companyName",document.querySelector("#company").value),t.append("area",document.querySelector("#area").value),t.append("title",document.querySelector("#jobTitle").value),fetch("/api/timelineData/work",{method:"POST",body:t,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>e.json().then((a=>{if(e.ok){let e=""===t.get("dateTo")?"Present":t.get("dateTo ");return addWorkData(a.ID,t.get("dateFrom"),e,t.get("companyName"),t.get("area"),t.get("title"),!0),void document.querySelector("#addWork").reset()}401!==e.status?showErrorMessage(a.error,"work"):window.location.href="./"}))))})),document.querySelector("#addProj").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;t.append("title",document.querySelector("#projTitle").value),t.append("isMainProject",document.querySelector("#isMainProject").checked?"true":"false"),t.append("information",document.querySelector("#projInfo").value),t.append("projectLink",document.querySelector("#projLink").value?document.querySelector("#projLink").value:"N/A"),t.append("gitLink",document.querySelector("#gitLink").value);let a=new FormData;a.append("img",document.querySelector("#projImg").files[0]);let l=0;fetch("/api/projectData",{method:"POST",body:t,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>e.json().then((o=>{if(e.ok)return"undefined"===a.get("img")?(addProject(o.ID,t.get("isMainProject"),"../imgs/placeholder.png",t.get("title"),t.get("information"),t.get("projectLink"),t.get("gitLink")),void document.querySelector("#addProj").reset()):(l=o.ID,fetch("/api/projectImage/"+o.ID,{method:"POST",body:a,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}));401!==e.status?showErrorMessage(o.error,"proj"):window.location.href="./"})).then((e=>e.json().then((a=>{if(e.ok)return addProject(l,t.get("isMainProject"),a.imgLocation,t.get("title"),t.get("information"),t.get("projectLink"),t.get("gitLink")),void document.querySelector("#addProj").reset();401!==e.status?showErrorMessage(a.error,"proj"):window.location.href="./"}))))))})),document.querySelector("#addPostForm").addEventListener("submit",(e=>{if(e.preventDefault(),""===editors.CKEditorAddPost.getData())return void showErrorMessage("Post body cannot be empty","addPost");let t=new FormData;t.append("title",document.querySelector("#postTitle").value),t.append("featured",document.querySelector("#isFeatured").checked?"1":"0"),t.append("abstract",document.querySelector("#postAbstract").value),t.append("body",editors.CKEditorAddPost.getData()),t.append("bodyText",viewToPlainText(editors.CKEditorAddPost.editing.view.document.getRoot())),t.append("dateCreated",(new Date).toISOString().slice(0,19).replace("T"," ")),t.append("categories",document.querySelector("#postCategories").value.toLowerCase()),t.append("headerImg",document.querySelector("#headerImg").files[0]),fetch("/api/blog/post",{method:"POST",body:t,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>e.json().then((a=>{if(e.ok)return document.querySelector("#addPostForm").reset(),editors.CKEditorAddPost.setData(""),addPostInfo(a.ID,t.get("title"),t.get("dateCreated"),t.get("dateModified")),void showSuccessMessage("Post added successfully","addPost");401!==e.status?e.json().then((e=>showErrorMessage(e.error,"addPost"))):window.location.href="./"}))))})),document.querySelector("#editPostForm").addEventListener("submit",(e=>{e.preventDefault();let t=document.querySelector("#editPostForm input[type='submit']").id;if(""===t)return void showErrorMessage("Currently not editing any post","editPost");if(""===editors.CKEditorEditPost.getData())return void showErrorMessage("Post body cannot be empty","editPost");let a={};a.title=document.querySelector("#editPostTitle").value,a.featured=document.querySelector("#editIsFeatured").checked?"1":"0",a.abstract=document.querySelector("#editPostAbstract").value,a.body=editors.CKEditorEditPost.getData(),a.bodyText=viewToPlainText(editors.CKEditorEditPost.editing.view.document.getRoot()),a.dateModified=(new Date).toISOString().slice(0,19).replace("T"," "),a.categories=document.querySelector("#editPostCategories").value.toLowerCase();let l=new FormData;l.append("headerImg",document.querySelector("#editHeaderImg").files[0]),fetch("/api/blog/post/"+t,{method:"PATCH",body:JSON.stringify(a),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>{if(e.ok)return"undefined"===l.get("headerImg")?(document.querySelector("#editPostForm").reset(),document.querySelector("#editPostForm input[type='submit']").id="",editors.CKEditorEditPost.setData(""),void showSuccessMessage("Post edited successfully","editPost")):fetch("/api/blog/headerImage/"+t,{method:"POST",body:l,headers:{Authorization:"Bearer "+localStorage.getItem("token")}});401!==e.status?e.json().then((e=>showErrorMessage(e.error,"editPost"))):window.location.href="./"})).then((e=>e.json().then((t=>{if(e.ok)return document.querySelector("#editPostForm").reset(),document.querySelector("#editPostForm input[type='submit']").id="",console.log(),editors.CKEditorEditPost.setData(""),void showSuccessMessage("Post edited successfully","editPost");401!==e.status?showErrorMessage(t.error.message,"editPost"):window.location.href="./"}))))})),document.querySelector("#goToCV").addEventListener("click",(()=>{textareaLoaded=!1,addActiveClass("goToCV"),goToPage("curriculumVitae")})),document.querySelector("#goToProjects").addEventListener("click",(()=>{textareaLoaded=!1,addActiveClass("goToProjects"),goToPage("projects")})),document.querySelector("#blog").addEventListener("click",(()=>{document.querySelector("nav.sideNav ul li.dropdown ul").classList.toggle("active"),document.querySelector("#blog i.fa").classList.toggle("fa-caret-down"),document.querySelector("#blog i.fa").classList.toggle("fa-caret-right")})),document.querySelector("#goToAddPost").addEventListener("click",(()=>{textareaLoaded=!1,addActiveClass("goToAddPost"),goToPage("addPost"),document.querySelector("#blog").classList.add("active")})),document.querySelector("#goToEditPost").addEventListener("click",(()=>{textareaLoaded=!1,addActiveClass("goToEditPost"),goToPage("editPost"),document.querySelector("#blog").classList.add("active")})),document.querySelector("#logout").addEventListener("click",(()=>{fetch("/api/user/logout").then((e=>{e.ok&&window.location.reload()}))})),document.querySelector("#eduError .close").addEventListener("click",(()=>document.querySelector("#eduError").classList.toggle("hidden"))),document.querySelector("#workError .close").addEventListener("click",(()=>document.querySelector("#workError").classList.toggle("hidden"))),document.querySelector("#projError .close").addEventListener("click",(()=>document.querySelector("#projError").classList.toggle("hidden"))),document.querySelector("#addPostError .close").addEventListener("click",(()=>document.querySelector("#addPostError").classList.toggle("hidden"))),document.querySelector("#addPostSuccess .close").addEventListener("click",(()=>document.querySelector("#addPostSuccess").classList.toggle("hidden"))),document.querySelector("#editPostError .close").addEventListener("click",(()=>document.querySelector("#editPostError").classList.toggle("hidden"))),document.querySelector("#editPostSuccess .close").addEventListener("click",(()=>document.querySelector("#editPostSuccess").classList.toggle("hidden"))); \ No newline at end of file +let dateOptions={month:"short",year:"numeric"},textareaLoaded=!1,editors={},posts=null;const smallPaddingElements=["figcaption","li"];function goToPage(e){document.querySelectorAll(".editor section").forEach((t=>{t.style.display="none",t.id===e&&(t.style.display="flex")}))}function viewToPlainText(e){let t="";if(e.is("$text")||e.is("$textProxy"))t=e.data;else if(e.is("element","br"))t="\n";else{let a=null;for(const l of e.getChildren()){const e=viewToPlainText(l);a&&(a.is("containerElement")||l.is("containerElement"))&&(smallPaddingElements.includes(a.name)||smallPaddingElements.includes(l.name)?t+="\n":t+="\n\n"),t+=e,a=l}}return t}function addActiveClass(e){document.querySelectorAll("nav.sideNav ul li a").forEach((t=>{t.classList.remove("active"),t.id===e&&t.classList.add("active")}))}function editProjectItem(e){document.querySelector(`#projectItem${e}`).classList.toggle("editing"),document.querySelector(`#title${e}proj`).toggleAttribute("disabled"),document.querySelector(`#info${e}proj`).toggleAttribute("disabled")}function createEditors(...e){e.forEach((e=>{ClassicEditor.create(document.querySelector(`#${e}`),{placeholder:"Write something amazing...",simpleUpload:{uploadUrl:"/api/blog/uploadPostImage",headers:{Authorization:"Bearer "+localStorage.getItem("token")}},style:{definitions:[{name:"Button Primary",element:"a",classes:["btn","btnPrimary"]},{name:"Button Primary",element:"button",classes:["btn","btnPrimary"]}]},codeBlock:{languages:[{language:"plaintext",label:"Plain text"},{language:"abap",label:"ABAP"},{language:"abnf",label:"ABNF"},{language:"actionscript",label:"ActionScript"},{language:"ada",label:"Ada"},{language:"agda",label:"Agda"},{language:"al",label:"AL"},{language:"antlr4",label:"ANTLR4"},{language:"apacheconf",label:"Apache Configuration"},{language:"apex",label:"Apex"},{language:"apl",label:"APL"},{language:"applescript",label:"AppleScript"},{language:"aql",label:"AQL"},{language:"arduino",label:"Arduino"},{language:"arff",label:"ARFF"},{language:"asciidoc",label:"AsciiDoc"},{language:"aspnet",label:"ASP.NET (C#)"},{language:"asm6502",label:"6502 Assembly"},{language:"autohotkey",label:"AutoHotkey"},{language:"autoit",label:"AutoIt"},{language:"bash",label:"Bash"},{language:"basic",label:"BASIC"},{language:"batch",label:"Batch"},{language:"bbcode",label:"BBcode"},{language:"bison",label:"Bison"},{language:"bnf",label:"BNF"},{language:"brainfuck",label:"Brainfuck"},{language:"brightscript",label:"BrightScript"},{language:"bro",label:"Bro"},{language:"c",label:"C"},{language:"concurnas",label:"Concurnas"},{language:"csharp",label:"C#"},{language:"cpp",label:"C++"},{language:"cil",label:"CIL"},{language:"clojure",label:"Clojure"},{language:"cmake",label:"CMake"},{language:"coffeescript",label:"CoffeeScript"},{language:"concurnas",label:"Concurnas"},{language:"crystal",label:"Crystal"},{language:"css-extras",label:"CSS Extras"},{language:"css",label:"CSS"},{language:"d",label:"D"},{language:"dart",label:"Dart"},{language:"dax",label:"DAX"},{language:"dhall",label:"Dhall"},{language:"diff",label:"Diff"},{language:"django",label:"Django/Jinja2"},{language:"dns-zone-file",label:"DNS zone file"},{language:"docker",label:"Docker"},{language:"ebnf",label:"EBNF"},{language:"editorconfig",label:"EditorConfig"},{language:"eiffel",label:"Eiffel"},{language:"ejs",label:"EJS"},{language:"elixir",label:"Elixir"},{language:"elm",label:"Elm"},{language:"etlua",label:"Embedded Lua"},{language:"erb",label:"ERB"},{language:"erlang",label:"Erlang"},{language:"excel-formula",label:"Excel Formula"},{language:"fsharp",label:"F#"},{language:"factor",label:"Factor"},{language:"firestore-security-rules",label:"Firestore security rules"},{language:"flow",label:"Flow"},{language:"fortran",label:"Fortran"},{language:"ftl",label:"FreeMarker Template Language"},{language:"gcode",label:"G-code"},{language:"gdscript",label:"GDScript"},{language:"gedcom",label:"GEDCOM"},{language:"gherkin",label:"Gherkin"},{language:"git",label:"Git"},{language:"glsl",label:"GLSL"},{language:"gml",label:"GameMaker Language"},{language:"go",label:"Go"},{language:"graphql",label:"GraphQL"},{language:"groovy",label:"Groovy"},{language:"haml",label:"Haml"},{language:"handlebars",label:"Handlebars"},{language:"haskell",label:"Haskell"},{language:"haxe",label:"Haxe"},{language:"hcl",label:"HCL"},{language:"hlsl",label:"HLSL"},{language:"http",label:"HTTP"},{language:"hpkp",label:"HTTP Public-Key-Pins"},{language:"hsts",label:"HTTP Strict-Transport-Security"},{language:"ichigojam",label:"IchigoJam"},{language:"icon",label:"Icon"},{language:"ignore",label:"Ignore"},{language:"inform7",label:"Inform 7"},{language:"ini",label:"Ini"},{language:"io",label:"Io"},{language:"j",label:"J"},{language:"java",label:"Java"},{language:"javadoc",label:"JavaDoc"},{language:"javadoclike",label:"JavaDoc-like"},{language:"javascript",label:"JavaScript"},{language:"javastacktrace",label:"Java stack trace"},{language:"jolie",label:"Jolie"},{language:"jq",label:"JQ"},{language:"js-extras",label:"JS Extras"},{language:"js-templates",label:"JS Templates"},{language:"jsdoc",label:"JSDoc"},{language:"json",label:"JSON"},{language:"json5",label:"JSON5"},{language:"jsonp",label:"JSONP"},{language:"jsstacktrace",label:"JS stack trace"},{language:"jsx",label:"React JSX"},{language:"julia",label:"Julia"},{language:"keyman",label:"Keyman"},{language:"kotlin",label:"Kotlin"},{language:"latex",label:"LaTeX"},{language:"latte",label:"Latte"},{language:"less",label:"Less"},{language:"lilypond",label:"LilyPond"},{language:"liquid",label:"Liquid"},{language:"lisp",label:"Lisp"},{language:"livescript",label:"LiveScript"},{language:"llvm",label:"LLVM IR"},{language:"log",label:"Log file"},{language:"lolcode",label:"LOLCODE"},{language:"lua",label:"Lua"},{language:"makefile",label:"Makefile"},{language:"markdown",label:"Markdown"},{language:"markup-templating",label:"Markup templating"},{language:"matlab",label:"MATLAB"},{language:"mel",label:"MEL"},{language:"mizar",label:"Mizar"},{language:"mongodb",label:"MongoDB"},{language:"monkey",label:"Monkey"},{language:"moonscript",label:"MoonScript"},{language:"n1ql",label:"N1QL"},{language:"n4js",label:"N4JS"},{language:"nand2tetris-hdl",label:"Nand To Tetris HDL"},{language:"nasm",label:"NASM"},{language:"neon",label:"NEON"},{language:"nginx",label:"nginx"},{language:"nim",label:"Nim"},{language:"nix",label:"Nix"},{language:"nsis",label:"NSIS"},{language:"objectivec",label:"Objective-C"},{language:"ocaml",label:"OCaml"},{language:"opencl",label:"OpenCL"},{language:"oz",label:"Oz"},{language:"parigp",label:"PARI/GP"},{language:"parser",label:"Parser"},{language:"pascal",label:"Pascal"},{language:"pascaligo",label:"Pascaligo"},{language:"pcaxis",label:"PC-Axis"},{language:"peoplecode",label:"PeopleCode"},{language:"perl",label:"Perl"},{language:"php",label:"PHP"},{language:"phpdoc",label:"PHPDoc"},{language:"php-extras",label:"PHP Extras"},{language:"plsql",label:"PL/SQL"},{language:"powerquery",label:"PowerQuery"},{language:"powershell",label:"PowerShell"},{language:"processing",label:"Processing"},{language:"prolog",label:"Prolog"},{language:"properties",label:".properties"},{language:"protobuf",label:"Protocol Buffers"},{language:"pug",label:"Pug"},{language:"puppet",label:"Puppet"},{language:"pure",label:"Pure"},{language:"purebasic",label:"PureBasic"},{language:"python",label:"Python"},{language:"q",label:"Q (kdb+ database)"},{language:"qml",label:"QML"},{language:"qore",label:"Qore"},{language:"r",label:"R"},{language:"racket",label:"Racket"},{language:"jsx",label:"React JSX"},{language:"tsx",label:"React TSX"},{language:"reason",label:"Reason"},{language:"regex",label:"Regex"},{language:"renpy",label:"Ren'py"},{language:"rest",label:"reST (reStructuredText)"},{language:"rip",label:"Rip"},{language:"roboconf",label:"Roboconf"},{language:"robotframework",label:"Robot Framework"},{language:"ruby",label:"Ruby"},{language:"rust",label:"Rust"},{language:"sas",label:"SAS"},{language:"sass",label:"Sass (Sass)"},{language:"scss",label:"Sass (Scss)"},{language:"scala",label:"Scala"},{language:"scheme",label:"Scheme"},{language:"shell-session",label:"Shell session"},{language:"smali",label:"Smali"},{language:"smalltalk",label:"Smalltalk"},{language:"smarty",label:"Smarty"},{language:"solidity",label:"Solidity (Ethereum)"},{language:"solution-file",label:"Solution file"},{language:"soy",label:"Soy (Closure Template)"},{language:"sparql",label:"SPARQL"},{language:"splunk-spl",label:"Splunk SPL"},{language:"sqf",label:"SQF: Status Quo Function (Arma 3)"},{language:"sql",label:"SQL"},{language:"stan",label:"Stan"},{language:"stata",label:"Stata"},{language:"step21",label:"STEP Part 21"},{language:"stylus",label:"Stylus"},{language:"swift",label:"Swift"},{language:"tap",label:"TAP"},{language:"tcl",label:"Tcl"},{language:"textile",label:"Textile"},{language:"toml",label:"TOML"},{language:"tt2",label:"Template Toolkit 2"},{language:"turtle",label:"Turtle"},{language:"twig",label:"Twig"},{language:"typescript",label:"TypeScript"},{language:"t4-cs",label:"T4 Text Templates (C#)"},{language:"t4-vb",label:"T4 Text Templates (VB)"},{language:"t4-templating",label:"T4 templating"},{language:"unrealscript",label:"UnrealScript"},{language:"vala",label:"Vala"},{language:"vbnet",label:"VB.Net"},{language:"velocity",label:"Velocity"},{language:"verilog",label:"Verilog"},{language:"vhdl",label:"VHDL"},{language:"vim",label:"vim"},{language:"visual-basic",label:"Visual Basic"},{language:"warpscript",label:"WarpScript"},{language:"wasm",label:"WebAssembly"},{language:"wiki",label:"Wiki markup"},{language:"xeora",label:"Xeora"},{language:"xojo",label:"Xojo (REALbasic)"},{language:"xquery",label:"XQuery"},{language:"yaml",label:"YAML"},{language:"zephir",label:"Zephir"}]}}).then((t=>{editors[e]=t})).catch((e=>{console.error("Oops, something went wrong!"),console.error("Please, report the following error on https://github.com/ckeditor/ckeditor5/issues with the build id and the error stack trace:"),console.warn("Build id: 1eo8ioyje2om-vgar4aghypdm"),console.error(e)}))}))}function editPostItem(e){posts.forEach((t=>{t.ID===e&&(document.querySelector("#editPostTitle").value=t.title,document.querySelector("#editIsFeatured").checked=1===t.featured,document.querySelector("#editPostCategories").value=t.categories,document.querySelector("#editPostAbstract").value=t.abstract,editors.CKEditorEditPost.setData(t.body),document.querySelector("#editPostForm input[type='submit']").id=e)}))}function showErrorMessage(e,t){document.querySelector(`#${t}Error`).classList.remove("hidden"),document.querySelector(`#${t}Error div`).innerText=e}function showSuccessMessage(e,t){document.querySelector(`#${t}Success`).classList.remove("hidden"),document.querySelector(`#${t}Success div`).innerText=e}function editCVItem(e){if(textareaLoaded=!1,document.querySelector(`#timelineItem${e}`).classList.toggle("editing"),e.includes("e"))return document.querySelector(`#grade${e}`).toggleAttribute("disabled"),void document.querySelector(`#course${e}`).toggleAttribute("disabled");document.querySelector(`#companyName${e}`).toggleAttribute("disabled"),document.querySelector(`#area${e}`).toggleAttribute("disabled"),document.querySelector(`#jobTitle${e}`).toggleAttribute("disabled")}function addEduData(e,t,a,l,o,n=!1){let r=e+"e",i=document.createElement("form");i.id="timelineItem"+r,i.classList.add("timelineItem"),i.onsubmit=t=>updateEduItem(e,t),i.innerHTML=`\n
\n \n \n
\n
\n \n -\n \n
\n

${new Date(t).toLocaleString("en-gb",dateOptions)} - ${new Date(a).toLocaleString("en-gb",dateOptions)}

\n
\n \n \n
\n
\n \n
\n \n \n \n `,n?document.querySelector("#edu").prepend(i):document.getElementById("edu").appendChild(i)}function addWorkData(e,t,a,l,o,n,r=!1){let i=e+"w",d=document.createElement("form");d.id="timelineItem"+i,d.classList.add("timelineItem"),d.onsubmit=t=>updateWorkItem(e,t),d.innerHTML=`\n
\n \n \n
\n
\n \n -\n \n
\n

${new Date(t).toLocaleString("en-gb",dateOptions)} - ${"Present"===a?"Present":new Date(a).toLocaleString("en-gb",dateOptions)}

\n
\n \n -\n \n
\n
\n \n
\n \n \n \n\t`,r?document.querySelector("#work").prepend(d):document.getElementById("work").appendChild(d)}function updateEduItem(e,t){t.preventDefault();let a={};a.dateFrom=document.querySelector(`#dateFrom${e}e`).value,a.dateTo=document.querySelector(`#dateTo${e}e`).value,a.grade=document.querySelector(`#grade${e}e`).value,a.course=document.querySelector(`#course${e}e`).value,fetch("/api/timelineData/edu/"+e,{method:"PATCH",body:JSON.stringify(a),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return document.querySelector(`#timelineHeader${e}e`).innerHTML=new Date(document.querySelector(`#dateFrom${e}e`).value).toLocaleString("en-gb",dateOptions)+" - "+new Date(document.querySelector(`#dateTo${e}e`).value).toLocaleString("en-gb",dateOptions),document.querySelector(`#timelineItem${e}e`).classList.toggle("editing"),document.querySelector(`#grade${e}e`).setAttribute("disabled",""),void document.querySelector(`#course${e}e`).setAttribute("disabled","");401!==t.status?t.json().then((t=>{document.querySelector(`#eduError${e}e`).classList.remove("hidden"),document.querySelector(`#eduError${e}e div`).innerHTML=t.error})):window.location.href="./"}))}function updateWorkItem(e,t){t.preventDefault();let a={};a.dateFrom=document.querySelector(`#dateFrom${e}w`).value,a.dateTo=document.querySelector(`#dateTo${e}w`).value,a.companyName=document.querySelector(`#companyName${e}w`).value,a.area=document.querySelector(`#area${e}w`).value,a.title=document.querySelector(`#jobTitle${e}w`).value,fetch("/api/timelineData/work/"+e,{method:"PATCH",body:JSON.stringify(a),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return document.querySelector(`#timelineHeader${e}w`).innerHTML=new Date(document.querySelector(`#dateFrom${e}w`).value).toLocaleString("en-gb",dateOptions)+" - "+new Date(document.querySelector(`#dateTo${e}w`).value).toLocaleString("en-gb",dateOptions),document.querySelector(`#timelineItem${e}w`).classList.toggle("editing"),document.querySelector(`#companyName${e}w`).setAttribute("disabled",""),document.querySelector(`#area${e}w`).setAttribute("disabled",""),void document.querySelector(`#jobTitle${e}w`).setAttribute("disabled","");401!==t.status?t.json().then((t=>{document.querySelector(`#workError${e}w`).classList.remove("hidden"),document.querySelector(`#workError${e}w div`).innerHTML=t.error})):window.location.href="./"}))}function deleteEduItem(e){fetch("/api/timelineData/edu/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#timelineItem${e}e`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}function deleteWorkItem(e){fetch("/api/timelineData/work/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#timelineItem${e}w`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}function updateProjectItem(e,t){t.preventDefault();let a={};a.title=document.querySelector(`#title${e}`).value,a.isMainProject=document.querySelector(`#isMainProject${e}`).checked?"true":"false",a.information=document.querySelector(`#info${e}`).value,a.projectLink=document.querySelector(`#viewProj${e}`).value,a.gitLink=document.querySelector(`#git${e}`).value;let l=new FormData;l.append("img",document.querySelector(`#img${e}`).files[0]),fetch("/api/projectData/"+e,{method:"PATCH",body:JSON.stringify(a),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return"undefined"===l.get("img")?("true"===a.isMainProject&&(document.querySelectorAll(".isMainProject input").forEach((e=>e.checked=!1)),document.querySelector(`#isMainProject${e}`).checked=!0,document.querySelector("#projList").prepend(document.querySelector(`#projectItem${e}`))),document.querySelector(`#projectItem${e}`).classList.toggle("editing"),document.querySelector(`#title${e}`).setAttribute("disabled",""),void document.querySelector(`#info${e}`).setAttribute("disabled","")):(console.log("updating image"),fetch("/api/projectImage/"+e,{method:"POST",body:l,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}));401!==t.status?t.json().then((t=>{document.querySelector(`#projError${e}`).classList.remove("hidden"),document.querySelector(`#projError${e} div`).innerHTML=t.error})):window.location.href="./"})).then((t=>t.json().then((a=>{if(t.ok)return"true"===a.isMainProject&&(document.querySelectorAll(".isMainProject input").forEach((e=>e.checked=!1)),document.querySelector(`#isMainProject${e}`).checked=!0,document.querySelector("#projList").prepend(document.querySelector(`#projectItem${e}`))),document.querySelector(`#projectItem${e}`).classList.toggle("editing"),document.querySelector(`#title${e}`).setAttribute("disabled",""),document.querySelector(`#info${e}`).setAttribute("disabled",""),void(document.querySelector(`#projectImage${e}`).src=a.imgLocation);401!==t.status?(document.querySelector(`#projError${e}`).classList.remove("hidden"),document.querySelector(`#projError${e} div`).innerHTML=a.error):window.location.href="./"}))))}function deleteProjectItem(e){fetch("/api/projectData/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#projectItem${e}`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}function addProject(e,t,a,l,o,n,r){let i=document.createElement("form"),d=e+"proj";if(i.id="projectItem"+e,i.classList.add("projItem"),i.onsubmit=t=>updateProjectItem(e,t),i.innerHTML=`\n
\n \n \n
\n image preivew of the project\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n \n \n \n `,"true"===t)return document.querySelectorAll(".isMainProject input").forEach((e=>e.checked=!1)),void document.querySelector("#projList").prepend(i);document.querySelector("#projList").appendChild(i)}function deletePostItem(e){fetch("/api/blog/post/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#postInfo${e}`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}function addPostInfo(e,t,a,l){let o=document.createElement("tr"),n=e+"post";o.id="postInfo"+e,o.innerHTML=`\n \n ${t}\n \n \n ${new Date(a).toLocaleDateString()}\n \n \n ${new Date(l).toLocaleDateString()}\n \n \n \n \n \n `,document.querySelector("#editPost table tbody").appendChild(o)}document.addEventListener("DOMContentLoaded",(()=>{fetch("/api/user/isLoggedIn").then((e=>{e.ok||(window.location.href="./")})),document.querySelector("#dateFromE").max=(new Date).toISOString().split("T")[0],document.querySelector("#dateFromW").max=(new Date).toISOString().split("T")[0],fetch("/api/timelineData/edu").then((e=>e.json().then((t=>{if(e.ok)for(let e=0;ee.json().then((t=>{if(e.ok)for(let e=0;ee.json().then((t=>{e.ok?t.forEach((e=>{addProject(e.ID,1===e.isMainProject?"true":"false",""===e.imgLocation?"../imgs/placeholder.png":e.imgLocation,e.title,e.information,e.projectLink,e.gitLink)})):document.querySelector("#projList").innerHTML="No project data found"})))),fetch("/api/blog/post").then((e=>e.json().then((t=>{e.ok&&(posts=t,t.forEach((e=>{addPostInfo(e.ID,e.title,e.dateCreated,e.dateModified)})))})))),createEditors("CKEditorAddPost","CKEditorEditPost")})),document.querySelector("body").addEventListener("click",(()=>{if(textareaLoaded)return;const e=document.querySelectorAll("main.editor textarea");for(let t=0;t{e.target.style.height="0",e.target.style.height=e.target.scrollHeight+15+"px"};textareaLoaded=!0})),document.querySelector("#navOpen").addEventListener("click",(e=>{document.querySelector("nav.sideNav").style.removeProperty("width"),document.querySelector("main.editor").style.removeProperty("margin-left"),e.target.style.removeProperty("visibility")})),document.querySelector("#navClose").addEventListener("click",(()=>{document.querySelector("nav.sideNav").style.width="0",document.querySelector("main.editor").style.marginLeft="0",document.querySelector("#navOpen").style.visibility="visible"})),document.querySelector("#addEdu").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;t.append("dateFrom",document.querySelector("#dateFromE").value),t.append("dateTo",document.querySelector("#dateToE").value),t.append("grade",document.querySelector("#grade").value),t.append("course",document.querySelector("#courseTitle").value),fetch("/api/timelineData/edu",{method:"POST",body:t,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>e.json().then((a=>{if(e.ok)return addEduData(a.ID,t.get("dateFrom"),t.get("dateTo"),t.get("grade"),t.get("course"),!0),void document.querySelector("#addEdu").reset();401!==e.status?showErrorMessage(a.error,"edu"):window.location.href="./"}))))})),document.querySelector("#addWork").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;t.append("dateFrom",document.querySelector("#dateFromW").value),t.append("dateTo",document.querySelector("#dateToW").value),t.append("companyName",document.querySelector("#company").value),t.append("area",document.querySelector("#area").value),t.append("title",document.querySelector("#jobTitle").value),fetch("/api/timelineData/work",{method:"POST",body:t,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>e.json().then((a=>{if(e.ok){let e=""===t.get("dateTo")?"Present":t.get("dateTo ");return addWorkData(a.ID,t.get("dateFrom"),e,t.get("companyName"),t.get("area"),t.get("title"),!0),void document.querySelector("#addWork").reset()}401!==e.status?showErrorMessage(a.error,"work"):window.location.href="./"}))))})),document.querySelector("#addProj").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;t.append("title",document.querySelector("#projTitle").value),t.append("isMainProject",document.querySelector("#isMainProject").checked?"true":"false"),t.append("information",document.querySelector("#projInfo").value),t.append("projectLink",document.querySelector("#projLink").value?document.querySelector("#projLink").value:"N/A"),t.append("gitLink",document.querySelector("#gitLink").value);let a=new FormData;a.append("img",document.querySelector("#projImg").files[0]);let l=0;fetch("/api/projectData",{method:"POST",body:t,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>e.json().then((o=>{if(e.ok)return"undefined"===a.get("img")?(addProject(o.ID,t.get("isMainProject"),"../imgs/placeholder.png",t.get("title"),t.get("information"),t.get("projectLink"),t.get("gitLink")),void document.querySelector("#addProj").reset()):(l=o.ID,fetch("/api/projectImage/"+o.ID,{method:"POST",body:a,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}));401!==e.status?showErrorMessage(o.error,"proj"):window.location.href="./"})).then((e=>e.json().then((a=>{if(e.ok)return addProject(l,t.get("isMainProject"),a.imgLocation,t.get("title"),t.get("information"),t.get("projectLink"),t.get("gitLink")),void document.querySelector("#addProj").reset();401!==e.status?showErrorMessage(a.error,"proj"):window.location.href="./"}))))))})),document.querySelector("#addPostForm").addEventListener("submit",(e=>{if(e.preventDefault(),""===editors.CKEditorAddPost.getData())return void showErrorMessage("Post body cannot be empty","addPost");let t=new FormData;t.append("title",document.querySelector("#postTitle").value),t.append("featured",document.querySelector("#isFeatured").checked?"1":"0"),t.append("abstract",document.querySelector("#postAbstract").value),t.append("body",editors.CKEditorAddPost.getData()),t.append("bodyText",viewToPlainText(editors.CKEditorAddPost.editing.view.document.getRoot())),t.append("dateCreated",(new Date).toISOString().slice(0,19).replace("T"," ")),t.append("categories",document.querySelector("#postCategories").value.toLowerCase()),t.append("headerImg",document.querySelector("#headerImg").files[0]),fetch("/api/blog/post",{method:"POST",body:t,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>e.json().then((a=>{if(e.ok)return document.querySelector("#addPostForm").reset(),editors.CKEditorAddPost.setData(""),addPostInfo(a.ID,t.get("title"),t.get("dateCreated"),t.get("dateModified")),void showSuccessMessage("Post added successfully","addPost");401!==e.status?e.json().then((e=>showErrorMessage(e.error,"addPost"))):window.location.href="./"}))))})),document.querySelector("#editPostForm").addEventListener("submit",(e=>{e.preventDefault();let t=document.querySelector("#editPostForm input[type='submit']").id;if(""===t)return void showErrorMessage("Currently not editing any post","editPost");if(""===editors.CKEditorEditPost.getData())return void showErrorMessage("Post body cannot be empty","editPost");let a={};a.title=document.querySelector("#editPostTitle").value,a.featured=document.querySelector("#editIsFeatured").checked?"1":"0",a.abstract=document.querySelector("#editPostAbstract").value,a.body=editors.CKEditorEditPost.getData(),a.bodyText=viewToPlainText(editors.CKEditorEditPost.editing.view.document.getRoot()),a.dateModified=(new Date).toISOString().slice(0,19).replace("T"," "),a.categories=document.querySelector("#editPostCategories").value.toLowerCase();let l=new FormData;l.append("headerImg",document.querySelector("#editHeaderImg").files[0]),fetch("/api/blog/post/"+t,{method:"PATCH",body:JSON.stringify(a),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((e=>{if(e.ok)return"undefined"===l.get("headerImg")?(document.querySelector("#editPostForm").reset(),document.querySelector("#editPostForm input[type='submit']").id="",editors.CKEditorEditPost.setData(""),void showSuccessMessage("Post edited successfully","editPost")):fetch("/api/blog/headerImage/"+t,{method:"POST",body:l,headers:{Authorization:"Bearer "+localStorage.getItem("token")}});401!==e.status?e.json().then((e=>showErrorMessage(e.error,"editPost"))):window.location.href="./"})).then((e=>e.json().then((t=>{if(e.ok)return document.querySelector("#editPostForm").reset(),document.querySelector("#editPostForm input[type='submit']").id="",console.log(),editors.CKEditorEditPost.setData(""),void showSuccessMessage("Post edited successfully","editPost");401!==e.status?showErrorMessage(t.error.message,"editPost"):window.location.href="./"}))))})),document.querySelector("#goToCV").addEventListener("click",(()=>{textareaLoaded=!1,addActiveClass("goToCV"),goToPage("curriculumVitae")})),document.querySelector("#goToProjects").addEventListener("click",(()=>{textareaLoaded=!1,addActiveClass("goToProjects"),goToPage("projects")})),document.querySelector("#blog").addEventListener("click",(()=>{document.querySelector("nav.sideNav ul li.dropdown ul").classList.toggle("active"),document.querySelector("#blog i.fa").classList.toggle("fa-caret-down"),document.querySelector("#blog i.fa").classList.toggle("fa-caret-right")})),document.querySelector("#goToAddPost").addEventListener("click",(()=>{textareaLoaded=!1,addActiveClass("goToAddPost"),goToPage("addPost"),document.querySelector("#blog").classList.add("active")})),document.querySelector("#goToEditPost").addEventListener("click",(()=>{textareaLoaded=!1,addActiveClass("goToEditPost"),goToPage("editPost"),document.querySelector("#blog").classList.add("active")})),document.querySelector("#logout").addEventListener("click",(()=>{fetch("/api/user/logout").then((e=>{e.ok&&window.location.reload()}))})),document.querySelector("#eduError .close").addEventListener("click",(()=>document.querySelector("#eduError").classList.toggle("hidden"))),document.querySelector("#workError .close").addEventListener("click",(()=>document.querySelector("#workError").classList.toggle("hidden"))),document.querySelector("#projError .close").addEventListener("click",(()=>document.querySelector("#projError").classList.toggle("hidden"))),document.querySelector("#addPostError .close").addEventListener("click",(()=>document.querySelector("#addPostError").classList.toggle("hidden"))),document.querySelector("#addPostSuccess .close").addEventListener("click",(()=>document.querySelector("#addPostSuccess").classList.toggle("hidden"))),document.querySelector("#editPostError .close").addEventListener("click",(()=>document.querySelector("#editPostError").classList.toggle("hidden"))),document.querySelector("#editPostSuccess .close").addEventListener("click",(()=>document.querySelector("#editPostSuccess").classList.toggle("hidden"))); \ No newline at end of file diff --git a/src/api/blog/blogData.php b/src/api/blog/blogData.php index 95dd912..a8f8c6f 100644 --- a/src/api/blog/blogData.php +++ b/src/api/blog/blogData.php @@ -444,22 +444,87 @@ class blogData if ($result) { - $bodyText = array_column($result, "bodyText"); - // go through each body plain text and get the sentence before, the sentence with the search term and the sentence after and append it to a new array - foreach ($bodyText as $key => $text) + for ($i = 0; $i < count($result); $i++) { - $text = strtolower($text); - $searchTerm = strtolower($searchTerm); - $pos = strpos($text, $searchTerm); - $start = strrpos(substr($text, 0, $pos), ".") + 1; - $end = strpos($text, ".", $pos); - $result[$key]["bodyText"] = substr($text, $start, $end - $start); + $result[$i]["abstract"] = $this->getShortPost($searchTerm, stripcslashes($result[$i]["bodyText"])); } - return $result; } return array("errorMessage" => "Error, could not find posts"); } + + /** + * Get the short post with the search term + * @param string $searchTerm - Search term + * @param $text - Body of the post as plain text + * @return string - Short post with the search term + */ + private function getShortPost(string $searchTerm, $text): string + { + $pattern = '/([,:;!?.-]+)/u'; + $parts = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + + $cleanedParts = []; + + foreach ($parts as $part) + { + $part = trim($part); // Remove leading/trailing spaces and newline characters + if (!empty($part)) + { + $cleanedParts[] = $part; + } + } + + $combinedParts = []; + $currentPart = ''; + + foreach ($cleanedParts as $part) + { + if (preg_match('/[,:;!?.-]/u', $part)) + { + $currentPart .= $part; + } + else + { + if (!empty($currentPart)) + { + $combinedParts[] = trim($currentPart); + } + $currentPart = rtrim($part); + } + } + + if (!empty($currentPart)) + { + $combinedParts[] = trim($currentPart); + } + + $result = ""; + + + for ($i = 0; $i < count($combinedParts); $i++) + { + $part = $combinedParts[$i]; + + if (stripos($part, $searchTerm) !== false) + { + $before = ($i > 0) ? $combinedParts[$i - 1] : ""; + $after = ($i < count($combinedParts) - 1) ? $combinedParts[$i + 1] : ""; + + if ($before === "" && $i > 0) + { + $before = $combinedParts[$i - 1]; + } + + $result = $before . " " . $part . " " . $after; + + // If the search term is found, we don't need to continue checking subsequent parts + break; + } + } + + return $result; + } } \ No newline at end of file diff --git a/src/api/blog/blogRoutes.php b/src/api/blog/blogRoutes.php index 7a7933a..d3c4201 100644 --- a/src/api/blog/blogRoutes.php +++ b/src/api/blog/blogRoutes.php @@ -254,7 +254,7 @@ class blogRoutes implements routesInterface } $featured = $data["featured"] === "true"; - $insertedID = $this->blogData->createPost($data["title"], $data["abstract"], $data["body"], $data["dateCreated"], $featured, $data["categories"], $headerImg); + $insertedID = $this->blogData->createPost($data["title"], $data["abstract"], $data["body"], $data["bodyText"], $data["dateCreated"], $featured, $data["categories"], $headerImg); if (!is_int($insertedID)) { // uh oh something went wrong diff --git a/src/blog/index.html b/src/blog/index.html index 60fe97d..838afd8 100644 --- a/src/blog/index.html +++ b/src/blog/index.html @@ -49,6 +49,22 @@ + +
diff --git a/src/blog/js/index.js b/src/blog/js/index.js index bed89d9..fffcaff 100644 --- a/src/blog/js/index.js +++ b/src/blog/js/index.js @@ -44,7 +44,6 @@ function goToURL(url) if (urlArray[2] === 'post') { // Create a new URL with the dynamic part - // window.history.pushState(null, null, url); loadIndividualPost(urlArray[urlArray.length - 1]).catch(err => console.log(err)); return; } @@ -52,14 +51,20 @@ function goToURL(url) if (urlArray[2] === 'category') { // Create a new URL with the dynamic part - // window.history.pushState(null, null, url); if (urlArray[3]) { loadPostsByCategory(urlArray[urlArray.length - 1]); return; } - loadAllCategories(); + loadAllCategories().catch(err => console.log(err)); + return; + } + + if (urlArray[2] === 'search' && urlArray[3]) + { + // Create a new URL with the dynamic part + loadSearchResults(urlArray[urlArray.length - 1]); return; } @@ -67,6 +72,26 @@ function goToURL(url) } +document.querySelector('#searchBtn').addEventListener('click', _ => +{ + let searchTerm = document.querySelector('#searchField').value; + if (searchTerm.length > 0) + { + window.history.pushState(null, null, `/blog/search/${searchTerm}`); + document.querySelector('#searchField').value = ''; + document.querySelector('#main').innerHTML = ''; + goToURL(`/blog/search/${searchTerm}`); + } +}); + +document.querySelector('#searchField').addEventListener('keyup', e => +{ + if (e.key === 'Enter') + { + document.querySelector('#searchBtn').click(); + } +}); + /** * Creates a large post element * @param post the post object @@ -116,25 +141,6 @@ function createLargePost(post) */ function loadHomeContent() { - let menuBar = document.createElement('div'); - menuBar.classList.add('menuBar'); - // language=HTML - menuBar.innerHTML = ` - - `; - document.querySelector('#main').appendChild(menuBar); - fetch('/api/blog/post').then(res => res.json().then(json => { for (let i = 0; i < json.length; i++) @@ -458,6 +464,34 @@ function loadPostsByCategory(category) })); } +function loadSearchResults(searchTerm) +{ + document.title = 'Rohit Pai - Search Results for ' + decodeURI(searchTerm); + fetch(`/api/blog/search/${searchTerm}`).then(res => res.json().then(json => + { + let main = document.querySelector('#main'); + let posts = document.createElement('section'); + posts.classList.add('catPosts'); + posts.id = 'searchResults'; + let h1 = document.createElement('h1'); + h1.innerHTML = 'Search Results'; + main.appendChild(h1); + for (let i = 0; i < json.length; i++) + { + let largePost = document.createElement('section'); + largePost.classList.add('largePost'); + if (i < json.length - 1) + { + largePost.classList.add('categoryPost'); + } + let outerContent = createLargePost(json[i]); + largePost.appendChild(outerContent); + posts.appendChild(largePost); + } + main.appendChild(posts); + })); +} + /** * Shows the 404 page */ diff --git a/src/css/nav.css b/src/css/nav.css index 63a0c8b..48540f3 100644 --- a/src/css/nav.css +++ b/src/css/nav.css @@ -64,7 +64,6 @@ nav ul li span { visibility: hidden; } - nav ul li .active::before, nav ul li .active::after { visibility: visible; diff --git a/src/editor/editor.html b/src/editor/editor.html index 2573b66..455afa1 100644 --- a/src/editor/editor.html +++ b/src/editor/editor.html @@ -200,10 +200,7 @@
- +
@@ -264,10 +261,7 @@
- +
diff --git a/src/editor/js/editor.js b/src/editor/js/editor.js index 00aadc3..e3f5f8f 100644 --- a/src/editor/js/editor.js +++ b/src/editor/js/editor.js @@ -486,11 +486,11 @@ function viewToPlainText(viewItem) // If item is `Text` or `TextProxy` simple take its text data. text = viewItem.data; } - else if (viewItem.is('element', 'img') && viewItem.hasAttribute('alt')) - { - // Special case for images - use alt attribute if it is provided. - text = viewItem.getAttribute('alt'); - } + // else if (viewItem.is('element', 'img') && viewItem.hasAttribute('alt')) + // { + // // Special case for images - use alt attribute if it is provided. + // text = viewItem.getAttribute('alt'); + // } else if (viewItem.is('element', 'br')) { // A soft break should be converted into a single line break (#8045).