diff --git a/brain/api/v1/ImagesAPI.inc.php b/brain/api/v1/ImagesAPI.inc.php new file mode 100644 index 0000000..aed3092 --- /dev/null +++ b/brain/api/v1/ImagesAPI.inc.php @@ -0,0 +1,30 @@ +getUploadedFiles(); + $path = date("Y") . "/" . date("m"); + + $uploadPath = "../public/assets/images/blog/" . $path; + + FileUploader::uploadFile($uploadPath, $image["post_image"]); + + $response = [ + "message" => "Image Added. Very slick", + "type" => "postImageAdded", + "url" => + "/assets/images/blog/" . + $path . + "/" . + $image["post_image"]->getClientFileName(), + ]; + + return $response; + } +} diff --git a/brain/controller/APIControl.inc.php b/brain/controller/APIControl.inc.php index a881b7e..ceae441 100644 --- a/brain/controller/APIControl.inc.php +++ b/brain/controller/APIControl.inc.php @@ -2,7 +2,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -//include "brain/data/Auth.inc.php"; +include "../brain/api/v1/ImagesAPI.inc.php"; class APIControl { @@ -18,7 +18,6 @@ class APIControl default: break; } - $response->getBody()->write(json_encode($result)); return $response->withHeader("Content-Type", "application/json"); } @@ -43,6 +42,33 @@ class APIControl break; case "logout": $result = Auth::logout($body); + break; + case "page": + //move methdology to its own API class + $task = $args["fourth"]; + $token = $request->getHeader("fipamo-access-token"); + if (Session::verifyToken($token[0])) { + switch ($task) { + case "delete": + case "add": + case "edit": + $result = (new Book("../content/pages"))->editPage( + $task, + $request + ); + break; + + case "add-entry-image": + $result = ImagesAPI::uploadImage($request); + break; + } + } else { + $result = [ + "message" => "API access denied, homie", + "type" => "API_ERROR", + ]; + } + break; default: $result = [ diff --git a/brain/controller/DashControl.inc.php b/brain/controller/DashControl.inc.php index 04930bf..d21a8b6 100644 --- a/brain/controller/DashControl.inc.php +++ b/brain/controller/DashControl.inc.php @@ -18,7 +18,12 @@ class DashControl switch (isset($args["second"]) ? $args["second"] : "index") { case "pages": $currentPage = isset($args["fourth"]) ? $args["fourth"] : 1; - $data = (new Book("../content/pages"))->getPages($currentPage, 4); + $filter = isset($args["third"]) ? $args["third"] : "all"; + $data = (new Book("../content/pages"))->getPages( + $currentPage, + 4, + $filter + ); $template = "dash/book.twig"; $pageOptions = [ "entryCount" => $data["entryCount"], diff --git a/brain/data/Book.inc.php b/brain/data/Book.inc.php index fbf325a..f9d25aa 100644 --- a/brain/data/Book.inc.php +++ b/brain/data/Book.inc.php @@ -33,23 +33,157 @@ class Book return $page; } + public function editPage($task, $request) + { + $content = $this->getContents(); + if ($task == "delete") { + $parsed = json_decode(file_get_contents("php://input"), true); + $body = find($content, ["uuid" => $parsed["id"]]); + } else { + $body = $request->getParsedBody(); + } + + $page = find($content, ["uuid" => $body["uuid"]]); + $image = $request->getUploadedFiles(); + $member = Session::get("member"); + + if ($task != "add") { + $path = + date("Y", date($page["rawCreated"])) . + "/" . + date("m", date($page["rawCreated"])); + } else { + $path = date("Y", date()) . "/" . date("m"); + } + + if (isset($image["feature_image"])) { + $feature = $image["feature_image"]->getClientFileName(); + FileUploader::uploadFile( + "../public/assets/images/blog/" . $path . "/", + $image["feature_image"] + ); + } else { + if (isset($body["feature_image"])) { + $url = explode("/", $body["feature_image"]); + $feature = + "/" . + $url[3] . + "/" . + $url[4] . + "/" . + $url[5] . + "/" . + $url[6] . + "/" . + $url[7] . + "/" . + $url[8]; + } else { + $feature = $body["feature"]; + } + } + + if ($task == "delete") { + $deleted = "true"; + $body["menu"] ? ($body["menu"] = "true") : ($body["menu"] = "false"); + $body["published"] + ? ($body["published"] = "true") + : ($body["published"] = "false"); + $body["featured"] + ? ($body["featured"] = "true") + : ($body["featured"] = "false"); + } else { + $deleted = !$page["deleted"] ? "false" : $page["deleted"]; + } + + $created = + $task != "add" + ? new \Moment\Moment($page["rawCreated"]) + : new \Moment\Moment(); + $updated = new \Moment\Moment(); + + $write = + "---\n" . + "id: " . + $body["id"] . + "\n" . + "uuid: " . + $body["uuid"] . + "\n" . + "title: " . + $body["title"] . + "\n" . + "feature: " . + $feature . + "\n" . + "path: " . + $path . + "\n" . + "layout: " . + $body["layout"] . + "\n" . + "tags: " . + $body["tags"] . + "\n" . + "author: " . + $member["handle"] . + "\n" . + "created: " . + $created->format("Y-m-d\TH:i:sP") . + "\n" . + "updated: " . + $updated->format("Y-m-d\TH:i:sP") . + "\n" . + "deleted: " . + $deleted . + "\n" . + "slug: " . + $body["slug"] . + "\n" . + "menu: " . + $body["menu"] . + "\n" . + "published: " . + $body["published"] . + "\n" . + "featured: " . + $body["featured"] . + "\n---\n" . + $body["content"]; + + // if layout is index, change path to file + + if ($body["layout"] == "index") { + $writePath = "../content/start/index.md"; + } else { + $writePath = "../content/pages/" . $path . "/" . $body["slug"] . ".md"; + } + + ($new = fopen($writePath, "w")) or die("Unable to open file!"); + fwrite($new, $write); + fclose($new); + + $response = [ + "message" => "File edited. Nice work", + "type" => $task == "write" ? "postUpdated" : "postAdded", + ]; + + return $response; + } + public function getPages(int $page, int $limit, string $sort = null) { $content = $this->getContents(); $published = filter($content, function ($item) { - return $item["published"] == "true"; + return $item["published"] == true && $item["deleted"] == false; }); $deleted = filter($content, function ($item) { - return $item["deleted"]; + return $item["deleted"] == true; }); $all = $content; - $filter = isset($sort) ? $sort : "all"; - - //echo $filter; - $filtered = []; switch ($filter) { case "published": $filtered = $published; @@ -61,9 +195,7 @@ class Book $filtered = $content; break; } - $numOfPages = ceil(count($filtered) / $limit); - $folder = []; if (count($filtered) != 0) { @@ -99,7 +231,7 @@ class Book "numOfPages" => $numOfPages, "entryCount" => count($filtered), "paginate" => [ - "sort" => $filter, + "sort" => $sort, "nextPage" => $next, "prevPage" => $prev, ], @@ -116,7 +248,6 @@ class Book $contents = []; foreach ($this->files as $file) { $doc = $parser->parse(file_get_contents($file), false); - $meta = $doc->getYAML(); $page = [ "id" => $meta["id"], @@ -129,6 +260,8 @@ class Book "author" => $meta["author"], "created" => date("Y M D d", $meta["created"]), "updated" => date("Y M D d", $meta["updated"]), + "rawCreated" => $meta["created"], + "rawUpdated" => $meta["updated"], "deleted" => $meta["deleted"], "menu" => $meta["menu"], "featured" => $meta["featured"], @@ -137,7 +270,6 @@ class Book "filePath" => $file, "content" => $doc->getContent(), ]; - //checks for duplicates $uuid = $meta["uuid"]; $found = current( diff --git a/brain/data/Session.inc.php b/brain/data/Session.inc.php index 12e8596..1d6d330 100644 --- a/brain/data/Session.inc.php +++ b/brain/data/Session.inc.php @@ -38,6 +38,24 @@ class Session } } + public static function verifyToken($token) + { + $data = json_decode(file_get_contents(self::$file), true); + if ($data["member"] != null) { + $secret = (new Settings())->getFolks("secret"); + if ( + Token::validate($token, $secret) && + Token::validateExpiration($token, $secret) + ) { + return true; + } else { + return false; + } + } else { + return false; + } + } + public static function set($key, $value) { $data = json_decode(file_get_contents(self::$file), true); diff --git a/brain/utility/FileUploader.inc.php b/brain/utility/FileUploader.inc.php new file mode 100644 index 0000000..5afbfc2 --- /dev/null +++ b/brain/utility/FileUploader.inc.php @@ -0,0 +1,29 @@ +getClientFileName(), $directory); + //$extension = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION); + + // see http://php.net/manual/en/function.random-bytes.php + //$basename = bin2hex(random_bytes(8)); + //$filename = sprintf("%s.%0.8s", $basename, $extension); + + $file->moveTo($directory . "/" . $file->getClientFileName()); + } catch (Error $e) { + echo "failed to upload image: " . $e->getMessage(); + throw new Error("Failed to upload image file"); + } + } +} diff --git a/brain/views/dash/page-edit.twig b/brain/views/dash/page-edit.twig index e299485..5e1278c 100644 --- a/brain/views/dash/page-edit.twig +++ b/brain/views/dash/page-edit.twig @@ -7,6 +7,7 @@ {% set id = page['id'] %} {% set uuid = page['uuid'] %} {% set slug = page['slug'] %} + {% set layout = page['layout'] %} {% set feature = page['feature'] %} {% set _title = page['title'] %} {% set tags = page['tags'] %} @@ -16,6 +17,7 @@ {% set id = '' %} {% set uuid = '' %} {% set slug = '' %} + {% set layout = 'pages' %} {% set feature = '' %} {% set title = '' %} {% set tags = '' %} @@ -32,7 +34,7 @@ {% endblock %} {% block mainContent %} -
+
{% if page['feature'] == null %} diff --git a/composer.json b/composer.json index 055928b..8eb6166 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "slim/twig-view": "^3.0", "mnapoli/front-yaml": "^1.8", "lodash-php/lodash-php": "^0.0.7", - "rbdwllr/reallysimplejwt": "^4.0" + "rbdwllr/reallysimplejwt": "^4.0", + "fightbulc/moment": "^1.33" } } diff --git a/composer.lock b/composer.lock index fbfaccd..030001b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0e243f32e05cb4ef6265ce19f141fdae", + "content-hash": "d5ef6d43f774049d093af6375d20ac11", "packages": [ { "name": "erusev/parsedown", @@ -112,6 +112,63 @@ }, "time": "2020-11-24T22:02:12+00:00" }, + { + "name": "fightbulc/moment", + "version": "1.33.0", + "source": { + "type": "git", + "url": "https://github.com/fightbulc/moment.php.git", + "reference": "435d68e481ab0a716358926fb51966e696d297e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fightbulc/moment.php/zipball/435d68e481ab0a716358926fb51966e696d297e3", + "reference": "435d68e481ab0a716358926fb51966e696d297e3", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36 || ^5.5 || ^6.5 || ^7.5 || ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Moment\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tino Ehrich", + "email": "tino@bigpun.me", + "role": "developer" + } + ], + "description": "Parse, validate, manipulate, and display dates in PHP w/ i18n support. Inspired by moment.js", + "keywords": [ + "date", + "display", + "format", + "i18n", + "locale", + "manipulate", + "moment", + "parse", + "time", + "translation", + "validate" + ], + "support": { + "issues": "https://github.com/fightbulc/moment.php/issues", + "source": "https://github.com/fightbulc/moment.php/tree/1.33.0" + }, + "time": "2021-03-27T13:10:08+00:00" + }, { "name": "lodash-php/lodash-php", "version": "0.0.7", diff --git a/public/index.php b/public/index.php index af63dca..e9af1c3 100644 --- a/public/index.php +++ b/public/index.php @@ -11,13 +11,14 @@ include "../brain/controller/RouteControl.inc.php"; include "../brain/data/Auth.inc.php"; include "../brain/utility/StringTools.inc.php"; include "../brain/data/Session.inc.php"; +include "../brain/utility/FileUploader.inc.php"; $app = AppFactory::create(); $twig = Twig::create("../brain/views/"); $app->add(TwigMiddleware::create($app, $twig)); //set up routing $app->get("/[{first}[/{second}[/{third}[/{fourth}]]]]", "\RouteControl:get"); -$app->post("/[{first}[/{second}[/{third}[/{fourt}]]]]", "\RouteControl:post"); +$app->post("/[{first}[/{second}[/{third}[/{fourth}]]]]", "\RouteControl:post"); //start the app $app->run(); diff --git a/src/com/controllers/DashManager.js b/src/com/controllers/DashManager.js index 57fc7f0..ad744c9 100644 --- a/src/com/controllers/DashManager.js +++ b/src/com/controllers/DashManager.js @@ -1,41 +1,41 @@ -import PostIndex from './PostIndex'; -import SettingsIndex from './SettingsIndex'; -import NaviIndex from './NavIndex'; +import PostIndex from "./PostIndex"; +import SettingsIndex from "./SettingsIndex"; +import NaviIndex from "./NavIndex"; export default class DashManager { - //-------------------------- - // constructor - //-------------------------- - constructor() { - this.currentDisplay = ''; - this.urlPieces = document.URL.split('/'); - this.chooseDisplay(this.urlPieces[5], this.urlPieces[6]); - } - //-------------------------- - // methods - //-------------------------- - start() {} + //-------------------------- + // constructor + //-------------------------- + constructor() { + this.currentDisplay = ""; + this.urlPieces = document.URL.split("/"); + this.chooseDisplay(this.urlPieces[4], this.urlPieces[5]); + } + //-------------------------- + // methods + //-------------------------- + start() {} - chooseDisplay(section, page) { - this.currentDisplay = ''; - switch (section) { - case 'page': - this.currentDisplay = new PostIndex(page); - break; - case 'settings': - this.currentDisplay = new SettingsIndex(); - break; - case 'navigation': - this.currentDisplay = new NaviIndex(); - break; + chooseDisplay(section, page) { + this.currentDisplay = ""; + switch (section) { + case "page": + this.currentDisplay = new PostIndex(page); + break; + case "settings": + this.currentDisplay = new SettingsIndex(); + break; + case "navigation": + this.currentDisplay = new NaviIndex(); + break; - default: - //just chill - break; - } - this.start(); - } - //-------------------------- - // event handlers - //-------------------------- + default: + //just chill + break; + } + this.start(); + } + //-------------------------- + // event handlers + //-------------------------- } diff --git a/src/com/controllers/PageEditor.js b/src/com/controllers/PageEditor.js index 89baabd..6212188 100644 --- a/src/com/controllers/PageEditor.js +++ b/src/com/controllers/PageEditor.js @@ -1,70 +1,74 @@ //TOOLS import FipamoAdminAPI, { - TASK_PAGE_CREATE, - TASK_PAGE_EDIT, - TASK_PAGE_DELETE -} from '../../libraries/FipamoAdminAPI'; -import * as DataEvent from '../events/DataEvent'; -import PageActions from '../actions/PageActions'; -import * as EditorEvent from '../events/EditorEvent'; + TASK_PAGE_CREATE, + TASK_PAGE_EDIT, + TASK_PAGE_DELETE, +} from "../../libraries/FipamoAdminAPI"; +import * as DataEvent from "../events/DataEvent"; +import PageActions from "../actions/PageActions"; +import * as EditorEvent from "../events/EditorEvent"; //import TinyDatePicker from 'tiny-date-picker'; -import TextEditor from '../ui/TextEditor'; -import Notfications from '../ui/Notifications'; +import TextEditor from "../ui/TextEditor"; +import Notfications from "../ui/Notifications"; const admin = new FipamoAdminAPI(); const notify = new Notfications(); export default class PostEditor { - //-------------------------- - // constructor - //-------------------------- - constructor() { - let self = this; - this.urlPieces = document.URL.split('/'); - this.post = []; - this.postID = null; - this.postUUID = null; - this.postLayout = null; - if (document.getElementById('post-edit-index').getAttribute('data-index')) { - this.postID = document.getElementById('post-edit-index').getAttribute('data-index'); - this.postUUID = document.getElementById('post-edit-index').getAttribute('data-uuid'); - this.postLayout = document - .getElementById('post-edit-index') - .getAttribute('data-layout'); - } - if (document.getElementById('edit-post-text')) { - this.editor = new TextEditor( - document.getElementById('edit-post-text'), - document.getElementById('header').offsetHeight + - document.getElementById('post-header').offsetHeight + - document.getElementById('post-feature').offsetHeight - ); - this.editor.addListener( - EditorEvent.EDITOR_DELETE, - () => this.handleEditorOptions(EditorEvent.EDITOR_DELETE), - false - ); - this.editor.addListener( - EditorEvent.EDITOR_UPLOAD_POST_IMAGE, - () => this.handleEditorOptions(EditorEvent.EDITOR_UPLOAD_POST_IMAGE), - false - ); - this.editor.addListener( - EditorEvent.EDITOR_UPDATE, - () => this.handleEditorOptions(EditorEvent.EDITOR_UPDATE), - false - ); - this.editor.addListener( - EditorEvent.EDITOR_SAVE, - () => this.handleEditorOptions(EditorEvent.EDITOR_SAVE), - false - ); - document.getElementById('post-image-upload').addEventListener( - 'change', - e => { - self.handleImageUpload(e.target.id, e.target.files); - }, - false - ); - /* + //-------------------------- + // constructor + //-------------------------- + constructor() { + let self = this; + this.urlPieces = document.URL.split("/"); + this.post = []; + this.postID = null; + this.postUUID = null; + this.postLayout = null; + if (document.getElementById("post-edit-index").getAttribute("data-index")) { + this.postID = document + .getElementById("post-edit-index") + .getAttribute("data-index"); + this.postUUID = document + .getElementById("post-edit-index") + .getAttribute("data-uuid"); + this.postLayout = document + .getElementById("post-edit-index") + .getAttribute("data-layout"); + } + if (document.getElementById("edit-post-text")) { + this.editor = new TextEditor( + document.getElementById("edit-post-text"), + document.getElementById("header").offsetHeight + + document.getElementById("post-header").offsetHeight + + document.getElementById("post-feature").offsetHeight + ); + this.editor.addListener( + EditorEvent.EDITOR_DELETE, + () => this.handleEditorOptions(EditorEvent.EDITOR_DELETE), + false + ); + this.editor.addListener( + EditorEvent.EDITOR_UPLOAD_POST_IMAGE, + () => this.handleEditorOptions(EditorEvent.EDITOR_UPLOAD_POST_IMAGE), + false + ); + this.editor.addListener( + EditorEvent.EDITOR_UPDATE, + () => this.handleEditorOptions(EditorEvent.EDITOR_UPDATE), + false + ); + this.editor.addListener( + EditorEvent.EDITOR_SAVE, + () => this.handleEditorOptions(EditorEvent.EDITOR_SAVE), + false + ); + document.getElementById("post-image-upload").addEventListener( + "change", + (e) => { + self.handleImageUpload(e.target.id, e.target.files); + }, + false + ); + /* TinyDatePicker(document.getElementById('post-date'), { mode: 'dp-below', format() { @@ -73,170 +77,180 @@ export default class PostEditor { }); */ - this.start(); - } - } - //-------------------------- - // methods - //-------------------------- - start() { - if (document.getElementById('featured-image-drop')) { - document - .getElementById('featured-image-drop') - .addEventListener('dragover', this.handleImageActions, false); - document - .getElementById('featured-image-drop') - .addEventListener('drop', this.handleImageActions, false); - document - .getElementById('featured-image-upload') - .addEventListener('change', e => this.handleImageActions(e), false); - if (document.getElementById('new-feature-upload')) { - document.getElementById('new-feature-upload').addEventListener('click', () => { - document.getElementById('featured-image-upload').click(); - }); - } - var optionButtons = document.querySelectorAll('.post-option-btn'); - for (var i = 0, length = optionButtons.length; i < length; i++) { - optionButtons[i].addEventListener('click', e => this.handlePostOptions(e), false); - } - } - } - //-------------------------- - // event handlers - //-------------------------- - handlePostOptions(e) { - let currentOption; - switch (e.target.id) { - case 'option-page-icon': - case 'option-menu-pin': - currentOption = document.getElementById('option-menu-pin'); - break; - case 'option-feature-icon': - case 'option-feature': - currentOption = document.getElementById('option-feature'); - break; - case 'option-published-icon': - case 'option-published': - currentOption = document.getElementById('option-published'); - break; - } - let active = currentOption.getAttribute('data-active'); - active == 'false' - ? currentOption.setAttribute('data-active', 'true') - : currentOption.setAttribute('data-active', 'false'); - } - handleEditorOptions(e) { - switch (e) { - case EditorEvent.EDITOR_SAVE: - case EditorEvent.EDITOR_UPDATE: - var task = ''; - e === EditorEvent.EDITOR_SAVE ? (task = TASK_PAGE_CREATE) : (task = TASK_PAGE_EDIT); - new PageActions() - .collectInfo(document.getElementById('featured-image-upload').files[0]) - .then(page => { - notify.alert('Writing down changes', null); - admin - .pageActions(task, page) - .then(r => { - if ( - r.type === DataEvent.PAGE_ERROR || - r.type === DataEvent.API_REQUEST_LAME - ) { - notify.alert(r.message, false); - } else { - if (r.type === DataEvent.PAGE_UPDATED) { - notify.alert(r.message, true); - } else { - notify.alert(r.message, true); - window.location = '/@/dashboard/page/edit/' + r.id; - } - } - }) - .catch(err => { - notify.alert(err, false); - }); - }); - break; - case EditorEvent.EDITOR_DELETE: - if (this.postLayout === 'index') { - notify.alert('Index cannot be deleted', false); - return; - } - if (confirm("AYE! You know you're deleting this post, right?")) { - let id = { id: this.postUUID }; - admin - .pageActions(TASK_PAGE_DELETE, id) - .then(() => { - window.location = '/@/dashboard/page/list/'; - }) - .catch(err => { - notify.alert(err, false); - }); - } else { - // Do nothing! - } - break; - case EditorEvent.EDITOR_UPLOAD_POST_IMAGE: - document.getElementById('post-image-upload').click(); - break; - } - } - handleImageActions(e) { - e.stopPropagation(); - e.preventDefault(); - switch (e.type) { - case 'dragover': - e.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy. - break; - case 'change': - case 'drop': - e.type == 'drop' - ? (PostEditor.uploadFiles = e.dataTransfer.files) - : (PostEditor.uploadFiles = e.target.files); - for (var i = 0, f; (f = PostEditor.uploadFiles[i]); i++) { - // Only process image files. - if (!f.type.match('image.*')) { - continue; - } - var reader = new FileReader(); - // Closure to capture the file information. - reader.onload = (function (theFile) { - return function (f) { - // Render thumbnail. - var image = document.createElement('img'); - image.src = f.target.result; - image.title = escape(theFile.name); - var span = document.createElement('div'); - span.innerHTML = [ - '' - ].join(''); - document.getElementById('featured-image-drop').innerHTML = ''; - document.getElementById('featured-image-drop').appendChild(image); - }; - })(f); - // Read in the image file as a data URL. - reader.readAsDataURL(f); - } - } - } - handleImageUpload(type, files) { - let self = this; - notify.alert('Uploading Image', null); - admin - .imageUpload(type, files) - .then(r => { - if (r.type == DataEvent.POST_IMAGE_ADDED) - self.editor.notify(EditorEvent.EDITOR_UPLOAD_POST_IMAGE, r.url); - notify.alert('Image Added to Entry', true); - }) - .catch(() => { - notify.alert('Uh oh. Image not added', false); - //console.log('ERROR', err); - }); - } + this.start(); + } + } + //-------------------------- + // methods + //-------------------------- + start() { + if (document.getElementById("featured-image-drop")) { + document + .getElementById("featured-image-drop") + .addEventListener("dragover", this.handleImageActions, false); + document + .getElementById("featured-image-drop") + .addEventListener("drop", this.handleImageActions, false); + document + .getElementById("featured-image-upload") + .addEventListener("change", (e) => this.handleImageActions(e), false); + if (document.getElementById("new-feature-upload")) { + document + .getElementById("new-feature-upload") + .addEventListener("click", () => { + document.getElementById("featured-image-upload").click(); + }); + } + var optionButtons = document.querySelectorAll(".post-option-btn"); + for (var i = 0, length = optionButtons.length; i < length; i++) { + optionButtons[i].addEventListener( + "click", + (e) => this.handlePostOptions(e), + false + ); + } + } + } + //-------------------------- + // event handlers + //-------------------------- + handlePostOptions(e) { + let currentOption; + switch (e.target.id) { + case "option-page-icon": + case "option-menu-pin": + currentOption = document.getElementById("option-menu-pin"); + break; + case "option-feature-icon": + case "option-feature": + currentOption = document.getElementById("option-feature"); + break; + case "option-published-icon": + case "option-published": + currentOption = document.getElementById("option-published"); + break; + } + let active = currentOption.getAttribute("data-active"); + active == "false" + ? currentOption.setAttribute("data-active", "true") + : currentOption.setAttribute("data-active", "false"); + } + handleEditorOptions(e) { + switch (e) { + case EditorEvent.EDITOR_SAVE: + case EditorEvent.EDITOR_UPDATE: + var task = ""; + e === EditorEvent.EDITOR_SAVE + ? (task = TASK_PAGE_CREATE) + : (task = TASK_PAGE_EDIT); + new PageActions() + .collectInfo( + document.getElementById("featured-image-upload").files[0] + ) + .then((page) => { + notify.alert("Writing down changes", null); + admin + .pageActions(task, page) + .then((r) => { + if ( + r.type === DataEvent.PAGE_ERROR || + r.type === DataEvent.API_REQUEST_LAME + ) { + notify.alert(r.message, false); + } else { + if (r.type === DataEvent.PAGE_UPDATED) { + notify.alert(r.message, true); + } else { + notify.alert(r.message, true); + window.location = "/@/dashboard/page/edit/" + r.id; + } + } + }) + .catch((err) => { + notify.alert(err, false); + }); + }); + break; + case EditorEvent.EDITOR_DELETE: + if (this.postLayout === "index") { + notify.alert("Index cannot be deleted", false); + return; + } + if (confirm("AYE! You know you're deleting this post, right?")) { + let id = { id: this.postUUID }; + admin + .pageActions(TASK_PAGE_DELETE, id) + .then(() => { + window.location = "/dashboard/pages"; + }) + .catch((err) => { + notify.alert(err, false); + }); + } else { + // Do nothing! + } + break; + case EditorEvent.EDITOR_UPLOAD_POST_IMAGE: + document.getElementById("post-image-upload").click(); + break; + } + } + handleImageActions(e) { + e.stopPropagation(); + e.preventDefault(); + switch (e.type) { + case "dragover": + e.dataTransfer.dropEffect = "copy"; // Explicitly show this is a copy. + break; + case "change": + case "drop": + e.type == "drop" + ? (PostEditor.uploadFiles = e.dataTransfer.files) + : (PostEditor.uploadFiles = e.target.files); + for (var i = 0, f; (f = PostEditor.uploadFiles[i]); i++) { + // Only process image files. + if (!f.type.match("image.*")) { + continue; + } + var reader = new FileReader(); + // Closure to capture the file information. + reader.onload = (function (theFile) { + return function (f) { + // Render thumbnail. + var image = document.createElement("img"); + image.src = f.target.result; + image.title = escape(theFile.name); + var span = document.createElement("div"); + span.innerHTML = [ + '', + ].join(""); + document.getElementById("featured-image-drop").innerHTML = ""; + document.getElementById("featured-image-drop").appendChild(image); + }; + })(f); + // Read in the image file as a data URL. + reader.readAsDataURL(f); + } + } + } + handleImageUpload(type, files) { + let self = this; + notify.alert("Uploading Image", null); + admin + .imageUpload(type, files) + .then((r) => { + if (r.type == DataEvent.POST_IMAGE_ADDED) + self.editor.notify(EditorEvent.EDITOR_UPLOAD_POST_IMAGE, r.url); + notify.alert("Image Added to Entry", true); + }) + .catch(() => { + notify.alert("Uh oh. Image not added", false); + //console.log('ERROR', err); + }); + } } PostEditor.uploadFiles = []; diff --git a/src/com/controllers/PostIndex.js b/src/com/controllers/PostIndex.js index 41d2798..9ff06f8 100644 --- a/src/com/controllers/PostIndex.js +++ b/src/com/controllers/PostIndex.js @@ -1,30 +1,30 @@ -import PageEditor from './PageEditor'; +import PageEditor from "./PageEditor"; export default class PostIndex { - //-------------------------- - // constructor - //-------------------------- - constructor(page) { - this.currentPage = null; - this.choosePage(page); - this.start(); - } - //-------------------------- - // methods - //-------------------------- - start() {} - choosePage(page) { - this.currentPage = ''; - switch (page) { - case 'edit': - case 'add': - this.currentPage = new PageEditor(); - break; - default: - //just chill - break; - } - } - //-------------------------- - // event handlers - //-------------------------- + //-------------------------- + // constructor + //-------------------------- + constructor(page) { + this.currentPage = null; + this.choosePage(page); + this.start(); + } + //-------------------------- + // methods + //-------------------------- + start() {} + choosePage(page) { + this.currentPage = ""; + switch (page) { + case "edit": + case "add": + this.currentPage = new PageEditor(); + break; + default: + //just chill + break; + } + } + //-------------------------- + // event handlers + //-------------------------- } diff --git a/src/libraries/FipamoAdminAPI.js b/src/libraries/FipamoAdminAPI.js index 9304123..56fd737 100644 --- a/src/libraries/FipamoAdminAPI.js +++ b/src/libraries/FipamoAdminAPI.js @@ -9,10 +9,10 @@ export const CONTENT_TYPE_JSON = "json"; export const CONTENT_TYPE_FORM = "x-www-form-urlencoded"; export const API_STATUS = "/api/v1/status"; export const API_GET_NAV = "/api/settings/nav"; -export const API_NEW_PAGE = "/api/v1/page/write/new"; +export const API_NEW_PAGE = "/api/v1/page/create"; export const API_EDIT_PAGE = "/api/v1/page/write"; export const API_DELETE_PAGE = "/api/v1/page/delete"; -export const API_IMAGE_UPLOAD = "/api/v1/page/add-post-image"; +export const API_IMAGE_UPLOAD = "/api/v1/page/add-entry-image"; export const API_SETTINGS_SYNC = "/api/v1/settings/sync"; export const API_UPLOAD_AVATAR = "/api/v1/settings/add-avatar"; export const API_UPLOAD_BACKGROUND = "/api/v1/settings/add-feature-background"; @@ -280,6 +280,7 @@ export default class APIUtils { request.open(requestType, requestURL, true); request.onload = () => { if (request.status == 200) { + //console.log("RESPONSE", request); let response = JSON.parse(request["response"]); resolve(response); } else { @@ -298,7 +299,7 @@ export default class APIUtils { eventType === DataEvent.API_BACKUP_RESTORE || eventType === DataEvent.API_REINDEX_PAGES ) - request.setRequestHeader("x-access-token", self.token); + request.setRequestHeader("fipamo-access-token", self.token); switch (contentType) { case CONTENT_TYPE_JSON: