started implementation of multiple file uploads and sorting

This commit is contained in:
Ro 2022-02-12 18:35:09 +00:00
parent 8f9021bb7d
commit 3c52bca8ba
21 changed files with 9549 additions and 818 deletions

138
.eslintrc
View file

@ -1,70 +1,70 @@
{ {
"parserOptions": { "parserOptions": {
"ecmaVersion": 7, "ecmaVersion": 7,
"sourceType": "module", "sourceType": "module",
"ecmaFeatures": {} "ecmaFeatures": {}
}, },
"rules": { "rules": {
"constructor-super": 2, "constructor-super": 2,
"for-direction": 2, "for-direction": 2,
"getter-return": 2, "getter-return": 2,
"no-case-declarations": 2, "no-case-declarations": 2,
"no-class-assign": 2, "no-class-assign": 2,
"no-compare-neg-zero": 2, "no-compare-neg-zero": 2,
"no-cond-assign": 2, "no-cond-assign": 2,
"no-console": 1, "no-console": 1,
"no-const-assign": 2, "no-const-assign": 2,
"no-constant-condition": 2, "no-constant-condition": 2,
"no-control-regex": 1, "no-control-regex": 1,
"no-debugger": 2, "no-debugger": 2,
"no-delete-var": 2, "no-delete-var": 2,
"no-dupe-args": 2, "no-dupe-args": 2,
"no-dupe-class-members": 2, "no-dupe-class-members": 2,
"no-dupe-keys": 2, "no-dupe-keys": 2,
"no-duplicate-case": 2, "no-duplicate-case": 2,
"no-empty": 2, "no-empty": 2,
"no-empty-character-class": 2, "no-empty-character-class": 2,
"no-empty-pattern": 2, "no-empty-pattern": 2,
"no-ex-assign": 2, "no-ex-assign": 2,
"no-extra-boolean-cast": 2, "no-extra-boolean-cast": 2,
"no-extra-semi": 2, "no-extra-semi": 2,
"no-fallthrough": 2, "no-fallthrough": 2,
"no-func-assign": 2, "no-func-assign": 2,
"no-global-assign": 2, "no-global-assign": 2,
"no-inner-declarations": 2, "no-inner-declarations": 2,
"no-invalid-regexp": 2, "no-invalid-regexp": 2,
"no-irregular-whitespace": 2, "no-irregular-whitespace": 2,
"no-mixed-spaces-and-tabs": 2, "no-mixed-spaces-and-tabs": 2,
"no-new-symbol": 2, "no-new-symbol": 2,
"no-obj-calls": 2, "no-obj-calls": 2,
"no-octal": 2, "no-octal": 2,
"no-redeclare": 2, "no-redeclare": 2,
"no-regex-spaces": 2, "no-regex-spaces": 2,
"no-self-assign": 2, "no-self-assign": 2,
"no-sparse-arrays": 2, "no-sparse-arrays": 2,
"no-this-before-super": 2, "no-this-before-super": 2,
"no-undef": 2, "no-undef": 2,
"no-unexpected-multiline": 2, "no-unexpected-multiline": 2,
"no-unreachable": 2, "no-unreachable": 2,
"no-unsafe-finally": 2, "no-unsafe-finally": 2,
"no-unsafe-negation": 2, "no-unsafe-negation": 2,
"no-unused-labels": 2, "no-unused-labels": 2,
"no-unused-vars": 2, "no-unused-vars": 1,
"no-useless-escape": 1, "no-useless-escape": 1,
"require-yield": 2, "require-yield": 2,
"use-isnan": 2, "use-isnan": 2,
"valid-typeof": 2, "valid-typeof": 2,
"no-duplicate-imports": 2 "no-duplicate-imports": 2
}, },
"env": { "env": {
"node": true, "node": true,
"browser": true, "browser": true,
"es6": true "es6": true
}, },
"globals": { "globals": {
"_": false, "_": false,
"hljs": false, "hljs": false,
"Sortable": false, "Sortable": false,
"Prism": false "Prism": false
} }
} }

7
.prettierignore Normal file
View file

@ -0,0 +1,7 @@
.babelrc
README.md
*.twig
*.sass
*.json
*.php
*.md

17
.prettierrc Normal file
View file

@ -0,0 +1,17 @@
{
"arrowParens": "avoid",
"bracketSpacing": true,
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"bracketSameLine": false,
"jsxSingleQuote": true,
"parser": "babel",
"proseWrap": "preserve",
"requirePragma": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"useTabs": true,
"tabWidth": 4,
"printWidth": 90
}

View file

@ -7,183 +7,194 @@ include "../brain/data/Book.inc.php";
class DashControl class DashControl
{ {
public static function start( public static function start(
ServerRequestInterface $request, ServerRequestInterface $request,
ResponseInterface $response, ResponseInterface $response,
array $args array $args
): ResponseInterface { ): ResponseInterface {
$view = Twig::fromRequest($request); $view = Twig::fromRequest($request);
$pageOptions = []; $pageOptions = [];
$template = ""; $template = "";
if (Setup::status()) { if (Setup::status()) {
switch (isset($args["second"]) ? $args["second"] : "index") { switch (isset($args["second"]) ? $args["second"] : "index") {
case "settings": case "settings":
if (Session::active()) { if (Session::active()) {
$config = new Settings(); $config = new Settings();
$settings = $config->getSettings(); $settings = $config->getSettings();
$themes = (new Themes())->getThemes(); //$config->getThemes(); $themes = (new Themes())->getThemes(); //$config->getThemes();
$template = "dash/settings.twig"; $template = "dash/settings.twig";
$member = Session::get("member"); $member = Session::get("member");
$form_token = Session::get("form_token"); $form_token = Session::get("form_token");
$updated = new \Moment\Moment($settings["global"]["last_backup"]); $updated = new \Moment\Moment($settings["global"]["last_backup"]);
$pageOptions = [ $pageOptions = [
"title" => "Dash Settings", "title" => "Dash Settings",
"private" => $settings["global"]["private"], "private" => $settings["global"]["private"],
"renderOnSave" => $settings["global"]["renderOnSave"], "renderOnSave" => $settings["global"]["renderOnSave"],
"background" => $settings["global"]["background"], "background" => $settings["global"]["background"],
"member" => $member, "member" => $member,
"ftoken" => $form_token, "ftoken" => $form_token,
"siteTitle" => $settings["global"]["title"], "siteTitle" => $settings["global"]["title"],
"baseUrl" => $settings["global"]["base_url"], "baseUrl" => $settings["global"]["base_url"],
"desc" => $settings["global"]["descriptions"], "desc" => $settings["global"]["descriptions"],
"lastBackup" => $updated->format("Y M D d"), "lastBackup" => $updated->format("Y M D d"),
"currentTheme" => $settings["global"]["theme"], "currentTheme" => $settings["global"]["theme"],
"themes" => $themes, "themes" => $themes,
"apiStatus" => isset($settings["global"]["externalAPI"]) "apiStatus" => isset($settings["global"]["externalAPI"])
? $settings["global"]["externalAPI"] ? $settings["global"]["externalAPI"]
: "false", : "false",
"dynamicRenderStatus" => isset( "dynamicRenderStatus" => isset(
$settings["global"]["dynamicRender"] $settings["global"]["dynamicRender"]
) )
? $settings["global"]["dynamicRender"] ? $settings["global"]["dynamicRender"]
: "false", : "false",
"mailOption" => $settings["email"]["active"], "mailOption" => $settings["email"]["active"],
"mailConfig" => $settings["email"], "mailConfig" => $settings["email"],
"status" => Session::active(), "status" => Session::active(),
]; ];
} else { } else {
header("Location: /dashboard"); header("Location: /dashboard");
die(); die();
} }
break; break;
case "navigation": case "navigation":
if (Session::active()) { if (Session::active()) {
$config = new Settings(); $config = new Settings();
$settings = $config->getSettings(); $settings = $config->getSettings();
$template = "dash/navigation.twig"; $template = "dash/navigation.twig";
$pageOptions = [ $pageOptions = [
"title" => "Edit Dash Navigation", "title" => "Edit Dash Navigation",
"status" => Session::active(), "status" => Session::active(),
"menu" => $settings["menu"], "menu" => $settings["menu"],
]; ];
} else { } else {
header("Location: /dashboard"); header("Location: /dashboard");
die(); die();
} }
break; break;
case "pages": case "pages":
if (Session::active()) { if (Session::active()) {
$currentPage = isset($args["fourth"]) ? $args["fourth"] : 1; $currentPage = isset($args["fourth"]) ? $args["fourth"] : 1;
$filter = isset($args["third"]) ? $args["third"] : "all"; $filter = isset($args["third"]) ? $args["third"] : "all";
$data = (new Book())->getPages($currentPage, 4, $filter); $data = (new Book())->getPages($currentPage, 4, $filter);
$template = "dash/book.twig"; $template = "dash/book.twig";
$pageOptions = [ $pageOptions = [
"entryCount" => $data["entryCount"], "entryCount" => $data["entryCount"],
"numOfPages" => $data["numOfPages"], "numOfPages" => $data["numOfPages"],
"currentPage" => $currentPage, "currentPage" => $currentPage,
"filter" => $data["paginate"]["sort"], "filter" => $data["paginate"]["sort"],
"stats" => $data["stats"], "stats" => $data["stats"],
"pages" => $data["pages"], "pages" => $data["pages"],
"paginate" => $data["paginate"], "paginate" => $data["paginate"],
"status" => Session::active(), "status" => Session::active(),
]; ];
} else { } else {
header("Location: /dashboard"); header("Location: /dashboard");
die(); die();
} }
break; break;
case "page": case "page":
if (Session::active()) { if (Session::active()) {
$template = "dash/page-edit.twig"; $template = "dash/page-edit.twig";
$mode = $args["third"]; $mode = $args["third"];
$uuid = $args["fourth"]; $uuid = $args["fourth"];
switch ($mode) { switch ($mode) {
case "edit": case "edit":
$page = (new Book())->findPageById($uuid); $page = (new Book())->findPageById($uuid);
$views = []; $views = [];
if (str_contains($page["layout"], "index")) { if (str_contains($page["layout"], "index")) {
$views = (new Themes())->getCustomIndex(); $views = (new Themes())->getCustomIndex();
} else { } else {
$views = (new Themes())->getCustomViews(); $views = (new Themes())->getCustomViews();
} }
$pageOptions = [
"title" => "Fipamo | Edit Page",
"page" => $page,
"mode" => $mode,
"token" => Session::get("form_token"),
"status" => Session::active(),
"views" => $views,
];
break;
case "preview":
$config = new Settings();
$settings = $config->getSettings();
$loader = new \Twig\Loader\FilesystemLoader(
"../content/themes"
);
$display = new \Twig\Environment($loader, []);
$book = new Book(); $imageList = explode(",", $page["feature"]);
$page = $book->findPageById($uuid); $images = [];
$pageOptions = Sorting::page($page); foreach ($imageList as $item) {
$preview = $image = trim($item);
$settings["global"]["theme"] . if ($item != null || $item != "") {
"/" . array_push($images, $item);
$page["layout"] . }
".twig"; }
$html = $display->render($preview, $pageOptions);
$response->getBody()->write($html); $pageOptions = [
return $response; "title" => "Fipamo | Edit Page",
break; "page" => $page,
default: "mode" => $mode,
$pageOptions = [ "token" => Session::get("form_token"),
"title" => "Fipamo | Create Page", "status" => Session::active(),
"token" => Session::get("form_token"), "images" => $images,
"mode" => $mode, "views" => $views,
"status" => Session::active(), ];
]; break;
case "preview":
$config = new Settings();
$settings = $config->getSettings();
$loader = new \Twig\Loader\FilesystemLoader(
"../content/themes"
);
$display = new \Twig\Environment($loader, []);
$book = new Book();
$page = $book->findPageById($uuid);
$pageOptions = Sorting::page($page);
$preview =
$settings["global"]["theme"] .
"/" .
$page["layout"] .
".twig";
$html = $display->render($preview, $pageOptions);
$response->getBody()->write($html);
return $response;
break;
default:
$pageOptions = [
"title" => "Fipamo | Create Page",
"token" => Session::get("form_token"),
"mode" => $mode,
"status" => Session::active(),
];
break;
}
} else {
header("Location: /dashboard");
die();
}
break;
case "logout":
Session::kill();
header("Location: /dashboard");
die();
break; break;
case "reset-password":
$template = "dash/reset-password.twig";
$pageOptions = [
"title" => "Reset Password",
];
break;
default:
$template = "dash/start.twig";
if (Session::active()) {
$pageOptions = [
"title" => "Welcome Back",
"status" => Session::active(),
"data" => (new Book())->getPages(1, 4),
];
} else {
$pageOptions = [
"title" => "Welcome to Fipamo",
"status" => Session::active(),
];
}
break;
} }
} else { } else {
header("Location: /dashboard"); $template = "dash/init.twig";
die(); $pageOptions = ["title" => "Fipamo Setup"];
} }
break;
case "logout":
Session::kill();
header("Location: /dashboard");
die();
break;
case "reset-password":
$template = "dash/reset-password.twig";
$pageOptions = [
"title" => "Reset Password",
];
break;
default: return $view->render($response, $template, $pageOptions);
$template = "dash/start.twig";
if (Session::active()) {
$pageOptions = [
"title" => "Welcome Back",
"status" => Session::active(),
"data" => (new Book())->getPages(1, 4),
];
} else {
$pageOptions = [
"title" => "Welcome to Fipamo",
"status" => Session::active(),
];
}
break;
}
} else {
$template = "dash/init.twig";
$pageOptions = ["title" => "Fipamo Setup"];
} }
return $view->render($response, $template, $pageOptions);
}
} }

View file

@ -40,7 +40,8 @@ class Book
} }
$page = find($content, ["uuid" => $body["uuid"]]); $page = find($content, ["uuid" => $body["uuid"]]);
$image = $request->getUploadedFiles(); $files = $request->getUploadedFiles();
$member = Session::get("member"); $member = Session::get("member");
if ($task != "create") { if ($task != "create") {
@ -52,13 +53,29 @@ class Book
$path = date("Y") . "/" . date("m"); $path = date("Y") . "/" . date("m");
} }
if (isset($image["feature_image"])) { if (isset($files)) {
//var_dump($files);
if ($task != "create") { if ($task != "create") {
$feature = $imageList = "";
"/assets/images/blog/" . $imagesPath = "/assets/images/blog/" . $path . "/";
$path . foreach ($files["page_files"] as $file) {
"/" . $type = $file->getClientMediaType();
$image["feature_image"]->getClientFileName(); switch ($type) {
case "image/jpeg":
case "image/png":
case "image/gif":
case "image/svg":
$imageList =
$imageList . $imagesPath . $file->getClientFileName() . ", ";
FileUploader::uploadFile(
"../public/assets/images/blog/" . $path . "/",
$file
);
break;
}
}
$feature = $imageList;
} else { } else {
$feature = $feature =
"/assets/images/blog/" . "/assets/images/blog/" .
@ -66,11 +83,6 @@ class Book
"/" . "/" .
$image["feature_image"]->getClientFileName(); $image["feature_image"]->getClientFileName();
} }
FileUploader::uploadFile(
"../public/assets/images/blog/" . $path . "/",
$image["feature_image"]
);
} else { } else {
if (isset($body["feature_image"])) { if (isset($body["feature_image"])) {
$url = explode("/", $body["feature_image"]); $url = explode("/", $body["feature_image"]);

View file

@ -85,7 +85,7 @@ class Contents
"extensions" => ["basic", "relative-a", "relative-image", "iframe"], "extensions" => ["basic", "relative-a", "relative-image", "iframe"],
"tags" => [ "tags" => [
"div" => [ "div" => [
"allowed_attributes" => ["class", "title"], "allowed_attributes" => ["class", "title", "id", "style"],
], ],
"img" => [ "img" => [
"allowed_attributes" => ["src", "alt", "title", "class"], "allowed_attributes" => ["src", "alt", "title", "class"],
@ -100,6 +100,15 @@ class Contents
$scrubbed = $sanitizer->sanitize($result->getContent()); $scrubbed = $sanitizer->sanitize($result->getContent());
$imageList = explode(",", $meta["feature"]);
$images = [];
foreach ($imageList as $item) {
$image = trim($item);
if ($item != null || $item != "") {
array_push($images, $item);
}
}
//sort attributes into page object //sort attributes into page object
$page = [ $page = [
"id" => $meta["id"], "id" => $meta["id"],
@ -124,6 +133,7 @@ class Contents
"filePath" => $file, "filePath" => $file,
"content" => $parsed->getContent(), "content" => $parsed->getContent(),
"html" => $scrubbed, "html" => $scrubbed,
"media" => $images,
]; ];
//checks for duplicates //checks for duplicates
$uuid = $meta["uuid"]; $uuid = $meta["uuid"];

View file

@ -12,6 +12,7 @@ class Render
public function __construct() public function __construct()
{ {
$config = new Settings(); $config = new Settings();
//TODO: Add theme folder to loader
$this->loader = new \Twig\Loader\FilesystemLoader("../content/themes"); $this->loader = new \Twig\Loader\FilesystemLoader("../content/themes");
$this->twig = new \Twig\Environment($this->loader, []); $this->twig = new \Twig\Environment($this->loader, []);
$settings = $config->getSettings(); $settings = $config->getSettings();
@ -51,6 +52,7 @@ class Render
} }
//copy current theme assets to public //copy current theme assets to public
//TODO: change to just grab directory contents for scripts and css
if (is_file("../public/assets/css/base.css")) { if (is_file("../public/assets/css/base.css")) {
unlink("../public/assets/css/base.css"); unlink("../public/assets/css/base.css");
} }

View file

@ -1,7 +1,7 @@
<div id="dash-login"> <div id="dash-login">
<div id="dash-form" class="dash-form"> <div id="dash-form" class="dash-form">
<img id="the-logo" src="/assets/images/global/fipamo-logo.svg"/> <img id="the-logo" src="/assets/images/global/fipamo-logo.svg"/>
<form id="login" class='login' name="login" action="/dashboard/login" method="POST"> <form id="login" class='login' name="login" method="post">
<input type="text" name="handle" class="form-control" placeholder="Handle" required "> <input type="text" name="handle" class="form-control" placeholder="Handle" required ">
<input type="password" name="password" class="form-control" placeholder="Password" required"> <input type="password" name="password" class="form-control" placeholder="Password" required">
<button id="login-btn" class='login-btn' type='submit'> <button id="login-btn" class='login-btn' type='submit'>

View file

@ -14,6 +14,7 @@
{% set content = page['content'] %} {% set content = page['content'] %}
{% set date = page['created'] %} {% set date = page['created'] %}
{% set updated = page['updated'] %} {% set updated = page['updated'] %}
{% set media = page['media'] %}
{% else %} {% else %}
{% set id = '' %} {% set id = '' %}
{% set uuid = '' %} {% set uuid = '' %}
@ -25,6 +26,7 @@
{% set content = '' %} {% set content = '' %}
{% set date = '' %} {% set date = '' %}
{% set updated = '' %} {% set updated = '' %}
{% set media = '' %}
{% endif %} {% endif %}
{% block title %} {% block title %}
@ -32,7 +34,7 @@
{% endblock %} {% endblock %}
{% block stylesheets %} {% block stylesheets %}
<link rel="stylesheet" type="text/css" href="/assets/css/dash.css?=qwert"> <link rel="stylesheet" type="text/css" href="/assets/css/dash.css?=weret">
{% endblock %} {% endblock %}
{% block mainContent %} {% block mainContent %}
@ -44,15 +46,26 @@
DRAG AND DROP IMAGE OR <label for="featured-image-upload">CLICK TO CHOSE</label> DRAG AND DROP IMAGE OR <label for="featured-image-upload">CLICK TO CHOSE</label>
</div> </div>
{% else %} {% else %}
<div id="featured-new-image-btn"> <div id="page-file-manager">
<button id="new-feature-upload"> <div id="page-file-wrapper">
<svg id="new-feature-upload" viewbox="0 0 20 20" class="icons"><use xlink:href="/assets/images/global/sprite.svg#entypo-image-inverted"/></svg> <div id="page-file-drop">
</button> <label for="page-files-upload">DRAG AND DROP FILES OR CLICK TO SELECT</label>
</div>
IMAGES AND VIDEO
<div id="page-images-list">
{% if media|length > 1 %}
{% for image in media %}
<div id="{{loop.index0}}" class="img-item" style="background: url({{ image }}) no-repeat center center / cover"></div>
{% endfor %}
{% else %}
<div id="0" class="img-item" style="background: url({{ media[0] }}) no-repeat center center / cover">
{% endif %}
</div>
<div id="page-files-list"></div>
</div>
</div> </div>
<div id="featured-image-drop">
<img id="featured-image" src="{{ feature }}"/>
</div>
{% endif %} {% endif %}
</div> </div>
@ -95,7 +108,7 @@
<span id="post-date" type="text"> <span id="post-date" type="text">
{{ updated }} {{ updated }}
</span> </span>
<input id="featured-image-upload" type="file" name="featured-image-upload"/> <input id="page-files-upload" type="file" name="page-files-upload" multiple/>
<input id="post-image-upload" type="file" name="post-image-upload"/> <input id="post-image-upload" type="file" name="post-image-upload"/>
<input id="form_token" name="token" type="hidden" value="{{ token }}"> <input id="form_token" name="token" type="hidden" value="{{ token }}">
</div> </div>
@ -119,5 +132,5 @@
{% endblock %} {% endblock %}
{% block javascripts %} {% block javascripts %}
<script src="/assets/scripts/Start.js" type="text/javascript"></script> <script src="/assets/scripts/Start.js?=dfgbg" type="text/javascript"></script>
{% endblock %} {% endblock %}

View file

@ -25,7 +25,7 @@
<br/> <br/>
{% if data["entryCount"] != 0 %} {% if data["entryCount"] != 0 %}
{% for page in data['pages'] %} {% for page in data['pages'] %}
<a href="/dashboard/page/edit/{{ page.uuid }}" id="{{ page.uuid }}" class="post-link" style="background: url({{ page.feature }}) no-repeat center center / cover"> <a href="/dashboard/page/edit/{{ page.uuid }}" id="{{ page.uuid }}" class="post-link" style="background: url({{ page.media[0] }}) no-repeat center center / cover">
<label> <label>
{{ page.title }} {{ page.title }}
</label> </label>

21
package-lock.json generated
View file

@ -27,7 +27,8 @@
"babel-cli": "^6.26.0", "babel-cli": "^6.26.0",
"eslint": "^8.5.0", "eslint": "^8.5.0",
"eslint-plugin-babel": "^5.3.1", "eslint-plugin-babel": "^5.3.1",
"parcel": "^2.0.1" "parcel": "^2.0.1",
"prettier": "^2.5.1"
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
@ -11558,6 +11559,18 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/prettier": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/prismjs": { "node_modules/prismjs": {
"version": "1.25.0", "version": "1.25.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz",
@ -23110,6 +23123,12 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"prettier": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true
},
"prismjs": { "prismjs": {
"version": "1.25.0", "version": "1.25.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz",

View file

@ -12,7 +12,8 @@
"babel-cli": "^6.26.0", "babel-cli": "^6.26.0",
"eslint": "^8.5.0", "eslint": "^8.5.0",
"eslint-plugin-babel": "^5.3.1", "eslint-plugin-babel": "^5.3.1",
"parcel": "^2.0.1" "parcel": "^2.0.1",
"prettier": "^2.5.1"
}, },
"dependencies": { "dependencies": {
"@babel/core": "^7.16.5", "@babel/core": "^7.16.5",

View file

@ -3164,31 +3164,59 @@ select {
#post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #post-options button[data-active=true] svg { #post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #post-options button[data-active=true] svg {
fill: #1D3040; fill: #1D3040;
} }
#post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #featured-image-upload, #post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #post-image-upload { #post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #page-files-upload, #post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #post-image-upload {
display: none; display: none;
} }
#post-edit-index #post-edit-index-wrapper #post-feature { #post-edit-index #post-edit-index-wrapper #post-feature {
width: 100%; width: 100%;
} }
#post-edit-index #post-edit-index-wrapper #post-feature #featured-image-drop { #post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager {
background: #f5ab35;
width: 100%;
min-height: 300px;
}
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper {
width: 100%;
max-width: 900px;
padding: 10px;
margin: 0 auto;
font-weight: bold;
font-color: #1D3040;
font-size: 1em;
}
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-file-drop {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
min-height: 200px; min-height: 100px;
background: black; background: #EFEBE3;
color: #1D3040; color: #1D3040;
vertical-align: middle; vertical-align: middle;
font-family: "Lucida Console", Monaco, monospace; border-radius: 5px;
margin: 0 0 10px 0;
} }
#post-edit-index #post-edit-index-wrapper #post-feature #featured-image-drop label { #post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-file-drop label {
cursor: pointer; cursor: pointer;
font-weight: 600px;
text-transform: capitalize;
} }
#post-edit-index #post-edit-index-wrapper #post-feature #featured-image-drop img { #post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-file-drop img {
width: 100%; width: 100%;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-images-list {
padding: 10px 0 0 0;
}
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-images-list .img-item {
height: 150px;
width: 23.8%;
border-radius: 3px;
margin: 0 10px 10px 0;
display: inline-block;
cursor: pointer;
}
#post-edit-index #post-edit-index-wrapper #post-feature #featured-new-image-btn { #post-edit-index #post-edit-index-wrapper #post-feature #featured-new-image-btn {
position: absolute; position: absolute;
margin: 20px; margin: 20px;

File diff suppressed because one or more lines are too long

View file

@ -1,213 +1,217 @@
import FipamoAdminAPI from "../libraries/FipamoAdminAPI"; import FipamoAdminAPI from '../libraries/FipamoAdminAPI';
import Maintenance from "./controllers/MaintenanceManager"; import Maintenance from './controllers/MaintenanceManager';
import DataUitls from "./utils/DataUtils"; import DataUitls from './utils/DataUtils';
import * as DataEvent from "./events/DataEvent"; import * as DataEvent from './events/DataEvent';
import DashManager from "./controllers/DashManager"; import DashManager from './controllers/DashManager';
import Notfications from "./ui/Notifications"; import Notfications from './ui/Notifications';
const data = new DataUitls(); const data = new DataUitls();
const notify = new Notfications(); const notify = new Notfications();
export default class Base { export default class Base {
//-------------------------- //--------------------------
// constructor // constructor
//-------------------------- //--------------------------
constructor() { constructor() {
this.processing = false; this.processing = false;
this.start(); this.start();
} }
//-------------------------- //--------------------------
// methods // methods
//-------------------------- //--------------------------
start() { start() {
if ( if (
document.getElementById("dash-form") || document.getElementById('dash-form') ||
document.getElementById("dash-init") document.getElementById('dash-init')
) { ) {
var options = document.getElementsByClassName("init-option"); var options = document.getElementsByClassName('init-option');
for (let index = 0; index < options.length; index++) { for (let index = 0; index < options.length; index++) {
options[index].addEventListener("click", (e) => this.handleOptions(e)); options[index].addEventListener('click', e =>
} this.handleOptions(e)
if (document.getElementById("dash-form")) { );
document }
.getElementById("login-btn") if (document.getElementById('dash-form')) {
.addEventListener("click", (e) => this.handleLogin(e)); document
} else { .getElementById('login-btn')
document .addEventListener('click', e => this.handleLogin(e));
.getElementById("init-blog") } else {
.addEventListener("click", (e) => this.handleSetup(e)); document
document .getElementById('init-blog')
.getElementById("blog-restore") .addEventListener('click', e => this.handleSetup(e));
.addEventListener("click", (e) => this.handleRestore(e)); document
} .getElementById('blog-restore')
} else if (document.getElementById("dash-reset")) { .addEventListener('click', e => this.handleRestore(e));
document }
.getElementById("get-secret-btn") } else if (document.getElementById('dash-reset')) {
.addEventListener("click", (e) => this.handleReset(e)); document
.getElementById('get-secret-btn')
.addEventListener('click', e => this.handleReset(e));
document document
.getElementById("reset-btn") .getElementById('reset-btn')
.addEventListener("click", (e) => this.handleReset(e)); .addEventListener('click', e => this.handleReset(e));
} else { } else {
new DashManager(); new DashManager();
} }
} }
//-------------------------- //--------------------------
// event handlers // event handlers
//-------------------------- //--------------------------
handleLogin(e) { handleLogin(e) {
if (this.processing) return; if (this.processing) return;
let self = this; let self = this;
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
let authForm = data.formDataToJSON(document.getElementById("login")); let authForm = data.formDataToJSON(document.getElementById('login'));
notify.alert("Looking, hold up", null); notify.alert('Looking, hold up', null);
let api = new FipamoAdminAPI(); let api = new FipamoAdminAPI();
this.processing = true; this.processing = true;
api api.login(authForm)
.login(authForm) .then(response => {
.then((response) => { self.processing = false;
self.processing = false; if (response.type === DataEvent.REQUEST_LAME) {
if (response.type === DataEvent.REQUEST_LAME) { notify.alert(response.message, false);
notify.alert(response.message, false); } else {
} else { notify.alert(response.message, true);
notify.alert(response.message, true); e.target.innerHTML = response.message;
e.target.innerHTML = response.message; setTimeout(() => {
setTimeout(() => { window.location = '/dashboard';
window.location = "/dashboard"; }, 500);
}, 500); }
} })
}) .catch(err => {
.catch((err) => { self.processing = false;
self.processing = false; notify.alert(err, false);
notify.alert(err, false); });
}); }
}
handleSetup(e) { handleSetup(e) {
if (this.processing) return; if (this.processing) return;
let self = this; let self = this;
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
let setUpForm = data.formDataToJSON(document.getElementById("init-form")); let setUpForm = data.formDataToJSON(
let mm = new Maintenance(); document.getElementById('init-form')
this.processing = true; );
mm.create(setUpForm) let mm = new Maintenance();
.then((response) => { this.processing = true;
if (response.type === DataEvent.API_INIT_LAME) { mm.create(setUpForm)
self.processing = false; .then(response => {
notify.alert(response.message, false); if (response.type === DataEvent.API_INIT_LAME) {
} else { self.processing = false;
self.processing = false; notify.alert(response.message, false);
notify.alert(response.message, true); } else {
setTimeout(() => { self.processing = false;
window.location = "/dashboard"; notify.alert(response.message, true);
}, 700); setTimeout(() => {
} window.location = '/dashboard';
}) }, 700);
.catch((err) => { }
self.processing = false; })
notify.alert(err, false); .catch(err => {
}); self.processing = false;
} notify.alert(err, false);
});
}
handleRestore(e) { handleRestore(e) {
if (this.processing) return; if (this.processing) return;
let self = this; let self = this;
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
let mm = new Maintenance(); let mm = new Maintenance();
var form = document.getElementById("init-restore"); var form = document.getElementById('init-restore');
this.processing = true; this.processing = true;
mm.restore(form) mm.restore(form)
.then((response) => { .then(response => {
if (response.type === DataEvent.REQUEST_LAME) { if (response.type === DataEvent.REQUEST_LAME) {
self.processing = false; self.processing = false;
notify.alert(response.message, false); notify.alert(response.message, false);
} else { } else {
self.processing = false; self.processing = false;
notify.alert(response.message, true); notify.alert(response.message, true);
setTimeout(() => { setTimeout(() => {
window.location = "/dashboard"; window.location = '/dashboard';
}, 1500); }, 1500);
} }
}) })
.catch((err) => { .catch(err => {
self.processing = false; self.processing = false;
notify.alert(err, false); notify.alert(err, false);
}); });
} }
handleReset(e) { handleReset(e) {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
let self = this; let self = this;
let mm = new Maintenance(); let mm = new Maintenance();
if (e.target.id == "get-secret-btn") { if (e.target.id == 'get-secret-btn') {
let data = { let data = {
email: document.getElementById("email").value, email: document.getElementById('email').value,
task: "retrieveSecret" task: 'retrieveSecret'
}; };
this.processing = true; this.processing = true;
mm.secret(data) mm.secret(data)
.then((response) => { .then(response => {
self.processing = false; self.processing = false;
if (response.secret) { if (response.secret) {
document.getElementById("secret").value = response.secret; document.getElementById('secret').value =
notify.alert(response.message, true); response.secret;
} else { notify.alert(response.message, true);
if (response.type == "mailSent") { } else {
notify.alert(response.message, true); if (response.type == 'mailSent') {
} else { notify.alert(response.message, true);
notify.alert(response.message, false); } else {
} notify.alert(response.message, false);
} }
}) }
.catch((err) => { })
self.processing = false; .catch(err => {
notify.alert(err, false); self.processing = false;
}); notify.alert(err, false);
} else { });
let data = { } else {
newPass: document.getElementById("new_password").value, let data = {
newPassConfirm: document.getElementById("new_password2").value, newPass: document.getElementById('new_password').value,
secret: document.getElementById("secret").value newPassConfirm: document.getElementById('new_password2').value,
}; secret: document.getElementById('secret').value
mm.newPass(data) };
.then((response) => { mm.newPass(data)
self.processing = false; .then(response => {
if (response.type == "passNotCreated") { self.processing = false;
notify.alert(response.message, false); if (response.type == 'passNotCreated') {
} else { notify.alert(response.message, false);
notify.alert(response.message, true); } else {
setTimeout(() => { notify.alert(response.message, true);
window.location = "/dashboard"; setTimeout(() => {
}, 1000); window.location = '/dashboard';
} }, 1000);
}) }
.catch((err) => { })
self.processing = false; .catch(err => {
notify.alert(err, false); self.processing = false;
}); notify.alert(err, false);
} });
} }
handleOptions(e) { }
e.stopPropagation(); handleOptions(e) {
e.preventDefault(); e.stopPropagation();
let init = document.getElementById("dash-init"); e.preventDefault();
let restore = document.getElementById("dash-restore"); let init = document.getElementById('dash-init');
if (e.target.id === "init-switch-restore") { let restore = document.getElementById('dash-restore');
init.style.display = "none"; if (e.target.id === 'init-switch-restore') {
init.style.visibility = "hidden"; init.style.display = 'none';
init.style.visibility = 'hidden';
restore.style.display = "flex"; restore.style.display = 'flex';
restore.style.visibility = "visible"; restore.style.visibility = 'visible';
} else { } else {
init.style.display = "flex"; init.style.display = 'flex';
init.style.visibility = "visible"; init.style.visibility = 'visible';
restore.style.display = "none"; restore.style.display = 'none';
restore.style.visibility = "hidden"; restore.style.visibility = 'hidden';
} }
} }
} }

View file

@ -7,7 +7,7 @@ export default class PostActions {
//-------------------------- //--------------------------
// methods // methods
//-------------------------- //--------------------------
collectInfo(image) { collectInfo(files) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let pageInfo = new FormData(); let pageInfo = new FormData();
let txt = document.createElement("textarea"); let txt = document.createElement("textarea");
@ -64,11 +64,14 @@ export default class PostActions {
"form_token", "form_token",
document.getElementById("form_token").value document.getElementById("form_token").value
); );
if (image != null || image != undefined) { if (files.length > 0 && files != null) {
if (image.type.match("image.*")) { for (var i = 0; i < files.length; i++) {
pageInfo.append("feature_image", image, image.name); var file = files[i];
} else { if (file.type.match("image.*")) {
reject("Not an image file"); pageInfo.append("page_files[]", file, file.name);
} else {
reject("Not an image file");
}
} }
} else { } else {
//check to see if image exists //check to see if image exists
@ -81,7 +84,7 @@ export default class PostActions {
//pageInfo.append("feature_image", null); //pageInfo.append("feature_image", null);
} }
} }
//console.log("FILES", files);
resolve(pageInfo); resolve(pageInfo);
}); });
} }

View file

@ -1,41 +1,41 @@
import PostIndex from "./PostIndex"; import PostIndex from './PostIndex';
import SettingsIndex from "./SettingsIndex"; import SettingsIndex from './SettingsIndex';
import NaviIndex from "./NavIndex"; import NaviIndex from './NavIndex';
export default class DashManager { export default class DashManager {
//-------------------------- //--------------------------
// constructor // constructor
//-------------------------- //--------------------------
constructor() { constructor() {
this.currentDisplay = ""; this.currentDisplay = '';
this.urlPieces = document.URL.split("/"); this.urlPieces = document.URL.split('/');
this.chooseDisplay(this.urlPieces[4], this.urlPieces[5]); this.chooseDisplay(this.urlPieces[4], this.urlPieces[5]);
} }
//-------------------------- //--------------------------
// methods // methods
//-------------------------- //--------------------------
start() {} start() {}
chooseDisplay(section, page) { chooseDisplay(section, page) {
this.currentDisplay = ""; this.currentDisplay = '';
switch (section) { switch (section) {
case "page": case 'page':
this.currentDisplay = new PostIndex(page); this.currentDisplay = new PostIndex(page);
break; break;
case "settings": case 'settings':
this.currentDisplay = new SettingsIndex(); this.currentDisplay = new SettingsIndex();
break; break;
case "navigation": case 'navigation':
this.currentDisplay = new NaviIndex(); this.currentDisplay = new NaviIndex();
break; break;
default: default:
//just chill //just chill
break; break;
} }
this.start(); this.start();
} }
//-------------------------- //--------------------------
// event handlers // event handlers
//-------------------------- //--------------------------
} }

View file

@ -1,84 +1,93 @@
//TOOLS //TOOLS
import FipamoAdminAPI, { import FipamoAdminAPI, {
TASK_PAGE_CREATE, TASK_PAGE_CREATE,
TASK_PAGE_EDIT, TASK_PAGE_EDIT,
TASK_PAGE_DELETE TASK_PAGE_DELETE
} from "../../libraries/FipamoAdminAPI"; } from '../../libraries/FipamoAdminAPI';
import Maintenance from "./MaintenanceManager"; import Maintenance from './MaintenanceManager';
import * as DataEvent from "../events/DataEvent"; import * as DataEvent from '../events/DataEvent';
import PageActions from "../actions/PageActions"; import PageActions from '../actions/PageActions';
import * as EditorEvent from "../events/EditorEvent"; import * as EditorEvent from '../events/EditorEvent';
//import TinyDatePicker from 'tiny-date-picker'; TODO: Reactivate for scheduled publishing //import TinyDatePicker from 'tiny-date-picker'; TODO: Reactivate for scheduled publishing
import TextEditor from "../ui/TextEditor"; import TextEditor from '../ui/TextEditor';
import Notfications from "../ui/Notifications"; import Notfications from '../ui/Notifications';
import FileManager from '../ui/FileManager';
const notify = new Notfications(); const notify = new Notfications();
export default class PostEditor { export default class PostEditor {
//-------------------------- //--------------------------
// constructor // constructor
//-------------------------- //--------------------------
constructor() { constructor() {
this.processing = false; this.processing = false;
let self = this; let self = this;
this.admin = new FipamoAdminAPI( this.admin = new FipamoAdminAPI(
null, null,
document.getElementById("notify-progress") document.getElementById('notify-progress')
); );
this.mm = new Maintenance( this.mm = new Maintenance(
null, null,
null, null,
document.getElementById("notify-progress") document.getElementById('notify-progress')
); );
this.urlPieces = document.URL.split("/"); this.urlPieces = document.URL.split('/');
this.post = []; this.post = [];
this.postID = null; this.postID = null;
this.postUUID = null; this.postUUID = null;
this.postLayout = null; this.postLayout = null;
if (document.getElementById("post-edit-index").getAttribute("data-index")) { this.fm = null;
this.postID = document if (
.getElementById("post-edit-index") document
.getAttribute("data-index"); .getElementById('post-edit-index')
this.postUUID = document .getAttribute('data-index')
.getElementById("post-edit-index") ) {
.getAttribute("data-uuid"); this.postID = document
this.postLayout = document .getElementById('post-edit-index')
.getElementById("post-edit-index") .getAttribute('data-index');
.getAttribute("data-layout"); this.postUUID = document
} .getElementById('post-edit-index')
if (document.getElementById("edit")) { .getAttribute('data-uuid');
this.editor = new TextEditor( this.postLayout = document
document.getElementById("edit"), .getElementById('post-edit-index')
document.getElementById("header").offsetHeight + .getAttribute('data-layout');
document.getElementById("post-header").offsetHeight + }
document.getElementById("post-feature").offsetHeight if (document.getElementById('edit')) {
); this.editor = new TextEditor(
this.editor.addListener( document.getElementById('edit'),
EditorEvent.EDITOR_DELETE, document.getElementById('header').offsetHeight +
() => this.handleEditorOptions(EditorEvent.EDITOR_DELETE), document.getElementById('post-header').offsetHeight +
false document.getElementById('post-feature').offsetHeight
); );
this.editor.addListener( this.editor.addListener(
EditorEvent.EDITOR_UPLOAD_POST_IMAGE, EditorEvent.EDITOR_DELETE,
() => this.handleEditorOptions(EditorEvent.EDITOR_UPLOAD_POST_IMAGE), () => this.handleEditorOptions(EditorEvent.EDITOR_DELETE),
false false
); );
this.editor.addListener( this.editor.addListener(
EditorEvent.EDITOR_UPDATE, EditorEvent.EDITOR_UPLOAD_POST_IMAGE,
() => this.handleEditorOptions(EditorEvent.EDITOR_UPDATE), () =>
false this.handleEditorOptions(
); EditorEvent.EDITOR_UPLOAD_POST_IMAGE
this.editor.addListener( ),
EditorEvent.EDITOR_SAVE, false
() => this.handleEditorOptions(EditorEvent.EDITOR_SAVE), );
false this.editor.addListener(
); EditorEvent.EDITOR_UPDATE,
document.getElementById("post-image-upload").addEventListener( () => this.handleEditorOptions(EditorEvent.EDITOR_UPDATE),
"change", false
(e) => { );
self.handleImageUpload(e.target.id, e.target.files); this.editor.addListener(
}, EditorEvent.EDITOR_SAVE,
false () => 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'), { TinyDatePicker(document.getElementById('post-date'), {
mode: 'dp-below', mode: 'dp-below',
format() { format() {
@ -87,202 +96,154 @@ export default class PostEditor {
}); });
*/ */
this.start(); this.start();
} }
} }
//-------------------------- //--------------------------
// methods // methods
//-------------------------- //--------------------------
start() { start() {
if (document.getElementById("featured-image-drop")) { if (document.getElementById('page-file-drop')) {
document //insert fileManager here
.getElementById("featured-image-drop") this.fm = new FileManager(
.addEventListener("dragover", this.handleImageActions, false); document.getElementById('page-file-drop'),
document document.getElementById('page-files-upload'),
.getElementById("featured-image-drop") document.getElementById('page-images-list'),
.addEventListener("drop", this.handleImageActions, false); document.getElementById('page-files-list')
document );
.getElementById("featured-image-upload") var optionButtons = document.querySelectorAll('.post-option-btn');
.addEventListener("change", (e) => this.handleImageActions(e), false); for (var i = 0, length = optionButtons.length; i < length; i++) {
if (document.getElementById("new-feature-upload")) { optionButtons[i].addEventListener(
document 'click',
.getElementById("new-feature-upload") e => this.handlePostOptions(e),
.addEventListener("click", () => { false
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( // event handlers
"click", //--------------------------
(e) => this.handlePostOptions(e), handlePostOptions(e) {
false let currentOption = null;
); switch (e.target.id) {
} case 'option-page-icon':
} case 'option-menu-pin':
} currentOption = document.getElementById('option-menu-pin');
//-------------------------- break;
// event handlers case 'option-feature-icon':
//-------------------------- case 'option-feature':
handlePostOptions(e) { currentOption = document.getElementById('option-feature');
let currentOption = null; break;
switch (e.target.id) { case 'option-published-icon':
case "option-page-icon": case 'option-published':
case "option-menu-pin": currentOption = document.getElementById('option-published');
currentOption = document.getElementById("option-menu-pin"); break;
break; }
case "option-feature-icon": if (currentOption != null) {
case "option-feature": let active = currentOption.getAttribute('data-active');
currentOption = document.getElementById("option-feature"); active == 'false'
break; ? currentOption.setAttribute('data-active', 'true')
case "option-published-icon": : currentOption.setAttribute('data-active', 'false');
case "option-published": }
currentOption = document.getElementById("option-published"); }
break; handleEditorOptions(e) {
} if (this.processing) return;
if (currentOption != null) { let self = this;
let active = currentOption.getAttribute("data-active"); switch (e) {
active == "false" case EditorEvent.EDITOR_SAVE:
? currentOption.setAttribute("data-active", "true") case EditorEvent.EDITOR_UPDATE:
: currentOption.setAttribute("data-active", "false"); var task = '';
} e === EditorEvent.EDITOR_SAVE
} ? (task = TASK_PAGE_CREATE)
handleEditorOptions(e) { : (task = TASK_PAGE_EDIT);
if (this.processing) return;
let self = this;
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) => {
self.processing = true;
notify.alert("Writing down changes", null);
self.admin
.pageActions(task, page)
.then((r) => {
self.processing = false;
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) => {
self.processing = false;
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?")) {
new PageActions()
.collectInfo(
document.getElementById("featured-image-upload").files[0]
)
.then((page) => {
self.processing = true;
this.admin
.pageActions(TASK_PAGE_DELETE, page)
.then(() => {
self.processing = false;
window.location = "/dashboard/pages";
})
.catch((err) => {
self.processing = false;
notify.alert(err, false);
});
})
.catch(() => {});
} 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.
//console.log("FILE TYPE", f.type);
if (!f.type.match("image.*")) {
alert("This is not an image. \nBad user. BAD.");
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 = [
'<img src="',
f.target.result,
'" title="',
escape(theFile.name),
'"/>'
].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);
self.mm new PageActions().collectInfo(this.fm.getFiles()).then(page => {
.imageUpload(type, files) self.processing = true;
.then((r) => { notify.alert('Writing down changes', null);
if (r.type == DataEvent.POST_IMAGE_ADDED) { self.admin
self.editor.notify(EditorEvent.EDITOR_UPLOAD_POST_IMAGE, r.url); .pageActions(task, page)
notify.alert("Image Added to Entry", true); .then(r => {
} else { self.processing = false;
notify.alert("Uh oh. Image not added", false); if (
} r.type === DataEvent.PAGE_ERROR ||
}) r.type === DataEvent.API_REQUEST_LAME
.catch(() => { ) {
notify.alert("Uh oh. Image not added", false); notify.alert(r.message, false);
//console.log('ERROR', err); } 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 => {
self.processing = false;
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?")
) {
new PageActions()
.collectInfo(
document.getElementById('featured-image-upload')
.files[0]
)
.then(page => {
self.processing = true;
this.admin
.pageActions(TASK_PAGE_DELETE, page)
.then(() => {
self.processing = false;
window.location = '/dashboard/pages';
})
.catch(err => {
self.processing = false;
notify.alert(err, false);
});
})
.catch(() => {});
} else {
// Do nothing!
}
break;
case EditorEvent.EDITOR_UPLOAD_POST_IMAGE:
document.getElementById('post-image-upload').click();
break;
}
}
handleImageUpload(type, files) {
let self = this;
notify.alert('Uploading Image', null);
self.mm
.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);
} else {
notify.alert('Uh oh. Image not added', false);
}
})
.catch(() => {
notify.alert('Uh oh. Image not added', false);
//console.log('ERROR', err);
});
}
} }
PostEditor.uploadFiles = []; PostEditor.uploadFiles = [];

146
src/com/ui/FileManager.js Normal file
View file

@ -0,0 +1,146 @@
import Sortable from 'sortablejs';
import DataUtils from '../utils/DataUtils';
export default class FileManager {
//--------------------------
// constructor
//--------------------------
constructor(upload, input, imageList, fileList) {
this.upload = upload;
this.input = input;
this.imageList = imageList;
this.fileList = fileList;
this.accetableFiles = ['image/jpeg', 'image/gif', 'image/png', 'image/svg'];
this.files = [];
this.sortedFiles = [];
this.storage = [];
this.start();
}
//--------------------------
// methods
//--------------------------
start() {
this.upload.addEventListener('dragover', e => this.handleFileActions(e), false);
this.upload.addEventListener('drop', e => this.handleFileActions(e), false);
this.input.addEventListener('change', e => this.handleFileActions(e), false);
Sortable.create(this.imageList, {
onUpdate: e => {
let currentFiles = []; //store current list
let items = e.target.children;
for (let index = 0; index < items.length; index++) {
var item = items[index];
currentFiles.push({
id: item.getAttribute('id'),
earl: item.style.backgroundImage.slice(4, -1).replace(/"/g, '')
});
}
this.reindexFiles(currentFiles, 0);
}
});
}
getFiles() {
return this.files;
}
reindexFiles(sortOrder, step) {
let count = sortOrder.length;
if (step == 0) this.files = [];
var utils = new DataUtils();
var path = sortOrder[step].earl.split('/');
utils.imgLoad(sortOrder[step].earl).then(blob => {
var fresh = new File([blob], path[6], { type: blob.type });
this.files.push(fresh);
if (this.files.length <= count - 1) {
this.reindexFiles(sortOrder, ++step);
} else {
//console.log('FILES', this.files);
}
});
}
sortFiles(files) {
var self = this;
this.files = []; //clear files array
this.imageList.innerHTML = '';
for (var i = 0, file; (file = files[i]); i++) {
var reader = new FileReader();
// Closure to capture the file information
reader.onload = (theFile => {
return function (f) {
// sort files
switch (theFile.type) {
case 'image/jpg':
case 'image/jpeg':
case 'image/gif':
case 'image/svg':
case 'image/png':
//create element and add to list
var image = document.createElement('img');
image.src = f.target.result;
image.title = escape(theFile.name);
var span = document.createElement('div');
span.style.background =
'url(' +
f.target.result +
') no-repeat center center / cover';
span.className = 'img-item';
image.setAttribute('id', i);
self.storage.push([
{
id: 'page_image' + i,
data: f.target.result,
type: theFile.type,
name: escape(theFile.name)
}
]);
self.imageList.appendChild(span);
//add to files list
self.files.push(theFile);
break;
}
};
})(file);
// Read in the image file as a data URL.
reader.readAsDataURL(file);
}
}
//--------------------------
// event handlers
//--------------------------
handleFileActions(e) {
e.stopPropagation();
e.preventDefault();
let self = this;
let rawList = [];
let sortedList = [];
let notOnTheList = [];
switch (e.type) {
case 'dragover':
e.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
break;
case 'change':
case 'drop':
e.type == 'drop'
? (rawList = e.dataTransfer.files)
: (rawList = e.target.files);
//this.sortFiles(freshList);
for (var i = 0, f; (f = rawList[i]); i++) {
// check witch files are cool to upload
if (this.accetableFiles.includes(f.type)) {
sortedList.push(f);
} else {
notOnTheList.push(f);
}
}
//send for sorting
self.sortFiles(sortedList);
break;
}
}
}

View file

@ -11,13 +11,13 @@ export default class DataUtils {
'use strict'; 'use strict';
// Create new promise with the Promise() constructor; // Create new promise with the Promise() constructor;
// This has as its argument a function with two parameters, resolve and reject // This has as its argument a function with two parameters, resolve and reject
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
// Standard XHR to load an image // Standard XHR to load an image
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('GET', url); request.open('GET', url);
request.responseType = 'blob'; request.responseType = 'blob';
// When the request loads, check whether it was successful // When the request loads, check whether it was successful
request.onload = function() { request.onload = function () {
if (request.status === 200) { if (request.status === 200) {
// If successful, resolve the promise by passing back the request response // If successful, resolve the promise by passing back the request response
resolve(request.response); resolve(request.response);
@ -25,12 +25,13 @@ export default class DataUtils {
// If it fails, reject the promise with a error message // If it fails, reject the promise with a error message
reject( reject(
new Error( new Error(
"Image didn't load successfully; error code:" + request.statusText "Image didn't load successfully; error code:" +
request.statusText
) )
); );
} }
}; };
request.onerror = function() { request.onerror = function () {
// Also deal with the case when the entire request fails to begin with // Also deal with the case when the entire request fails to begin with
// This is probably a network error, so reject the promise with an appropriate message // This is probably a network error, so reject the promise with an appropriate message
reject(new Error('There was a network error.')); reject(new Error('There was a network error.'));
@ -42,14 +43,14 @@ export default class DataUtils {
loadImage(src) { loadImage(src) {
'use strict'; 'use strict';
let self = this; let self = this;
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
// Get a reference to the body element, and create a new image object // Get a reference to the body element, and create a new image object
var myImage = new Image(); var myImage = new Image();
myImage.crossOrigin = ''; // or "anonymous" myImage.crossOrigin = ''; // or "anonymous"
// Call the function with the URL we want to load, but then chain the // Call the function with the URL we want to load, but then chain the
// promise then() method on to the end of it. This contains two callbacks // promise then() method on to the end of it. This contains two callbacks
self.imgLoad(src).then( self.imgLoad(src).then(
function(response) { function (response) {
// The first runs when the promise resolves, with the request.reponse specified within the resolve() method. // The first runs when the promise resolves, with the request.reponse specified within the resolve() method.
var imageURL = window.URL.createObjectURL(response); var imageURL = window.URL.createObjectURL(response);
resolve(imageURL); resolve(imageURL);
@ -58,7 +59,7 @@ export default class DataUtils {
//body.appendChild(myImage); //body.appendChild(myImage);
// The second runs when the promise is rejected, and logs the Error specified with the reject() method. // The second runs when the promise is rejected, and logs the Error specified with the reject() method.
}, },
function(Error) { function (Error) {
reject(Error); reject(Error);
} }
); );

View file

@ -258,30 +258,54 @@
svg svg
fill: $primary fill: $primary
#featured-image-upload, #post-image-upload #page-files-upload, #post-image-upload
display: none display: none
#post-feature #post-feature
width: 100% width: 100%
#featured-image-drop #page-file-manager
display: flex background: $tertiary
align-items: center
justify-content: center
width: 100% width: 100%
min-height: 200px min-height: 300px
background: color.adjust($primary, $lightness: -50%) #page-file-wrapper
color: $primary
vertical-align: middle
font-family: $monoType
label
cursor: pointer
img
width: 100% width: 100%
margin: 0 max-width: 900px
padding: 0 padding: 10px
margin: 0 auto
font-weight: bold
font-color: $primary
font-size: 1em
#page-file-drop
display: flex
align-items: center
justify-content: center
width: 100%
min-height: 100px
background: $white
color: $primary
vertical-align: middle
border-radius: 5px
margin: 0 0 10px 0
label
cursor: pointer
font-weight: 600px
text-transform: capitalize
img
width: 100%
margin: 0
padding: 0
#page-images-list
padding: 10px 0 0 0
.img-item
height: 150px
width: 23.8%
border-radius: 3px
margin: 0 10px 10px 0
display: inline-block
cursor: pointer
#featured-new-image-btn #featured-new-image-btn
position: absolute position: absolute