CSS Overhaul Part 1

This one is a doozy, so let's breakt it down into what areas where
touched.

-   updated package json to remove unneeded dependencies.
-   rebuilt file uploading to simply a very convuluted process
-   began proces to replace icons with https://tabler-icons.io
-   began process of removing the need for css preprocessor and using
    pure css
        - login completed
        - dashboard index completed
        - page edit ui completed
- page edit ui text editor tweaked so syntax highlighting is cleaner and
  more accurate

The settings and navigation UIs still remain and then polishing the
responsive for the new css structure
This commit is contained in:
Ro 2023-03-23 13:55:34 -07:00
parent ec1dc49ba1
commit 07b422a9c3
No known key found for this signature in database
GPG key ID: 29B551CDBD4D3B50
49 changed files with 24179 additions and 28127 deletions

2
.gitignore vendored
View file

@ -12,7 +12,7 @@ public/*
public/assets/*
!public/assets/css
public/assets/css/*
!public/assets/css/dash.css
!public/assets/css/dash
!public/assets/scripts
public/assets/scripts/*
!public/assets/scripts/Start.js

View file

@ -1,6 +1,3 @@
{
"extends": [
"stylelint-config-standard-scss",
"stylelint-config-prettier-scss"
]
"extends": ["stylelint-config-standard"]
}

53
brain/api/v1/FilesAPI.php Normal file
View file

@ -0,0 +1,53 @@
<?php
namespace brain\api\v1;
use brain\utility\FileUploader;
class FilesAPI
{
public function __construct()
{
}
public static function uploadFiles($request, $type = null)
{
$upload = $request->getUploadedFiles(); //grab uploaded files
$file = $upload['upload_files'][0]; //front end sends one by one for progress tracking, so grab first
$type = $file->getClientMediaType();
$filesPath = '';
$path = date('Y') . '/' . date('m');
$response = [];
switch ($type) {
case 'image/jpeg':
case 'image/png':
case 'image/gif':
case 'image/svg':
$filesPath = '/assets/images/blog/' . $path . '/';
break;
case 'video/mp4':
$filesPath = '/assets/video/blog/' . $path . '/';
break;
case 'audio/mpeg':
$filesPath = '/assets/sound/blog/' . $path . '/';
break;
case 'application/pdf':
case 'text/plain':
case 'text/rtf':
$filesPath = '/assets/docs/blog/' . $path . '/';
break;
}
FileUploader::uploadFile('../public' . $filesPath, $file);
$response = [
'message' => "File Uploaded. Great!",
"filePath" => $filesPath . urlencode($file->getClientFileName()),
"fileName" => urlencode($file->getClientFileName()),
'type' => $type,
];
return $response;
}
}

View file

@ -111,7 +111,7 @@ class PagesAPI
case 'delete':
case 'create':
case 'write':
$body = $request->getParsedBody();
$body = json_decode(file_get_contents("php://input"), true);
$passed = true;
if (!isset($body['form_token'])) {
$result = [
@ -134,12 +134,15 @@ class PagesAPI
'featured',
'published',
'form_token',
'feature_image',
'imageList',
"fileList",
"remote"
];
foreach ($body as $key => $item) {
if (!in_array($key, $keys)) {
//found unnecessary key, so reject submission
var_dump($key);
$passed = false;
}
}

View file

@ -6,6 +6,7 @@ use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use brain\api\v1\AuthAPI;
use brain\api\v1\PagesAPI;
use brain\api\v1\FilesAPI;
use brain\api\v1\SettingsAPI;
use brain\api\v1\InitAPI;
use brain\api\v1\MailerAPI;
@ -188,6 +189,24 @@ class APIControl
];
}
break;
case "files":
$token = $request->getHeader('fipamo-access-token');
if (isset($token[0])) {
if (Session::verifyToken($token[0])) {
$result = FilesAPI::uploadFiles($request, $args);
} else {
$result = [
'message' => 'Invalid token, API access denied, homie',
'type' => 'API_ERROR',
];
}
} else {
$result = [
'message' => 'No token, API access denied, homie',
'type' => 'API_ERROR',
];
}
break;
case 'settings':
if (isset($body)) {

View file

@ -7,6 +7,7 @@ use brain\data\Session;
use brain\data\Settings;
use brain\data\Themes;
use brain\utility\Setup;
use brain\utility\Sorting;
use Carbon\Carbon;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
@ -151,16 +152,15 @@ class DashControl
$config = new Settings();
$settings = $config->getSettings();
$loader = new \Twig\Loader\FilesystemLoader(
'../content/themes'
'../content/themes/' . $settings['global']['theme'] .
'/'
);
$display = new \Twig\Environment($loader, []);
$book = new Book();
$page = $book->findPageById($uuid);
$pageOptions = Sorting::page($page);
$preview = $settings['global']['theme'] .
'/' .
$page['layout'] .
$preview = $page['layout'] .
'.twig';
$html = $display->render($preview, $pageOptions);
$response->getBody()->write($html);

View file

@ -33,13 +33,15 @@ class RouteControl
): ResponseInterface {
switch (isset($args['first']) ? $args['first'] : 'index') {
case 'api':
//$result = APIControl::post($request, $response, $args);
return APIControl::post($request, $response, $args);
break;
default:
//echo "YES";
//return IndexControl::start($request, $response, $args);
break;
$result = [
'message' => "Nothing matches this route. That's unfortunate",
'type' => 'TASK_NONE',
];
$response->getBody()->write(json_encode($result));
return $response->withHeader('Content-Type', 'application/json');
}
}
}

View file

@ -5,7 +5,6 @@ namespace brain\data;
use Carbon\Carbon;
use brain\utility\DocTools;
use brain\utility\StringTools;
use brain\utility\FileUploader;
use function _\find;
use function _\filter;
@ -39,13 +38,8 @@ class Book
public function editPage($task, $request)
{
$content = $this->getContents();
if ($task == 'delete') {
// $parsed = json_decode(file_get_contents("php://input"), true);
$body = json_decode(file_get_contents("php://input"), true);
//$body = find($content, ["uuid" => $parsed["id"]]);
$body = $request->getParsedBody();
} else {
$body = $request->getParsedBody();
}
$page = find($content, ['uuid' => $body['uuid']]);
$files = $request->getUploadedFiles();
@ -63,65 +57,6 @@ class Book
$page_feature = '';
$page_files = '';
if (isset($files['page_files'])) {
$imageList = '';
$fileList = '';
//var_dump($files['page_files']);
foreach ($files['page_files'] as $file) {
$type = $file->getClientMediaType();
//var_dump($type);
switch ($type) {
case 'image/jpeg':
case 'image/png':
case 'image/gif':
case 'image/svg':
$imagesPath = '/assets/images/blog/' . $path . '/';
$imageList = $imageList . $imagesPath . urlencode($file->getClientFileName()) . ', ';
FileUploader::uploadFile(
'../public/assets/images/blog/' . $path . '/',
$file
);
break;
case 'video/mp4':
$videosPath = '/assets/video/blog/' . $path . '/';
$imageList = $imageList . $videosPath . urlencode($file->getClientFileName()) . ', ';
FileUploader::uploadFile(
'../public/assets/video/blog/' . $path . '/',
$file
);
break;
case 'audio/mpeg':
$soundPath = '/assets/sound/blog/' . $path . '/';
$fileList = $fileList . $soundPath . urlencode($file->getClientFileName()) . ', ';
FileUploader::uploadFile(
'../public/assets/sound/blog/' . $path . '/',
$file
);
break;
case 'application/pdf':
case 'text/plain':
case 'text/rtf':
$docPath = '/assets/docs/blog/' . $path . '/';
$fileList = $fileList . $docPath . urlencode($file->getClientFileName()) . ', ';
FileUploader::uploadFile(
'../public/assets/docs/blog/' . $path . '/',
$file
);
break;
}
}
$page_feature = $imageList;
$page_files = $fileList;
} else {
// if no files, just reset string from page object
$page_feature = $page['feature'];
$page_files = $page['files'];
}
if ($task == 'delete') {
$deleted = 'true';
$body['menu'] = 'false';
@ -141,8 +76,8 @@ class Book
$body['id'] = $id;
$body['uuid'] = $uuid;
$body['feature'] = $page_feature;
$body['files'] = $page_files;
//$body['feature'] = $page_feature;
//$body['files'] = $page_files;
$body['path'] = $path;
$body['author'] = $member['handle'];
$body['created'] = $created->format("Y-m-d\TH:i:sP");

View file

@ -99,10 +99,10 @@ class DocTools
"'" .
"\n" .
'feature: ' .
$object['feature'] .
$object['imageList'] .
"\n" .
'files: ' .
$object['files'] .
$object['fileList'] .
"\n" .
'path: ' .
$object['path'] .

View file

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="theme-color" content="#FFFFFF"/>
<title>
{% block title %}
{{ title }}
{% endblock %}
</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
<div id="notifications" class="notifications">
<div id="notify-message" class="notify-message">
<div id="notify-good" class="notify-icon">
<svg viewbox="0 0 20 20" class="icons"><use xlink:href="/assets/images/global/sprite.svg#entypo-emoji-flirt"/></svg>
</div>
<div id="notify-lame" class="notify-icon">
<svg viewbox="0 0 20 20" class="icons"><use xlink:href="/assets/images/global/sprite.svg#entypo-emoji-sad"/></svg>
</div>
<div id="notify-working" class="notify-icon">
<svg id="notify-working-icon" viewbox="0 0 20 20" class="icons"><use xlink:href="/assets/images/global/sprite.svg#entypo-cog"/></svg>
</div>
<div id="notify-text">
<div id="notify-progress"></div>
<p id="message-text">MESSAGE TEXT</p>
</div>
</div>
</div>
<div id="main-content" class="main-container">
<section id="dash-index-content">
{% if status %}
<header id="header">
<div id="wrapper">
{% apply spaceless %}
<div id="left">
<a href="/dashboard"><img id="the-logo" src="/assets/images/global/fipamo-logo.svg"/></a>
</div>
<div id="right">
{% if status %}
{% apply spaceless %}
{{ include("dash/partials/navigation.twig") }}
{% endapply %}
{% endif %}
</div>
{% endapply %}
</div>
</header>
{% endif %}
{% apply spaceless %}
{% block mainContent %}{% endblock %}
{% endapply %}
</section>
</div>
<footer></footer>
{% block javascripts %}{% endblock %}
</body>
</html>

View file

@ -11,25 +11,6 @@
{% block stylesheets %}{% endblock %}
</head>
<body>
<div id="notifications" class="notifications">
<div id="notify-message" class="notify-message">
<div id="notify-good" class="notify-icon">
<svg viewbox="0 0 20 20" class="icons"><use xlink:href="/assets/images/global/sprite.svg#entypo-emoji-flirt"/></svg>
</div>
<div id="notify-lame" class="notify-icon">
<svg viewbox="0 0 20 20" class="icons"><use xlink:href="/assets/images/global/sprite.svg#entypo-emoji-sad"/></svg>
</div>
<div id="notify-working" class="notify-icon">
<svg id="notify-working-icon" viewbox="0 0 20 20" class="icons"><use xlink:href="/assets/images/global/sprite.svg#entypo-cog"/></svg>
</div>
<div id="notify-text">
<div id="notify-progress"></div>
<p id="message-text">MESSAGE TEXT</p>
</div>
</div>
</div>
{% if status %}
<header>
{% apply spaceless %}
@ -37,8 +18,10 @@
<div role="nav-left">
<a href="/dashboard"><img id="the-logo" src="/assets/images/global/fipamo-logo.svg"/></a>
</div>
<div>
NOTIFICATIONS
<div role="notifications">
{% apply spaceless %}
{{ include("dash/partials/notifications.twig") }}
{% endapply %}
</div>
<div role="nav-right">
{% if status %}
@ -57,6 +40,6 @@
{% endapply %}
</main>
<footer></footer>
{% block javascripts %}{% endblock %}
<script src="/assets/scripts/start.js?=dfdfdfse" type="text/javascript"></script>
</body>
</html>

View file

@ -13,7 +13,8 @@
<div id="post-index-wrapper">
<div id="post-index-header">
<div id="post-index-header-left">
{{ filter }} Pages
{{ filter }}
Pages
</div>
<div id="post-index-header-right">
<a href="/dashboard/pages/all" title="view all pages">
@ -96,7 +97,3 @@
</div>
</div>
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js" type="text/javascript"></script>
{% endblock %}

View file

@ -44,5 +44,5 @@
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js?=sdfsdf" type="text/javascript"></script>
<script src="/assets/scripts/start.js?=sdfsdf" type="text/javascript"></script>
{% endblock %}

View file

@ -37,7 +37,3 @@
</div>
</div>
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js?=cvfggt" type="text/javascript"></script>
{% endblock %}

View file

@ -36,45 +36,43 @@
{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="/assets/css/dash.css?=dfdf">
<link rel="stylesheet" type="text/css" href="/assets/css/dash/start.css?=vdthg">
{% endblock %}
{% block mainContent %}
<div id="post-edit-index" data-index="{{ id }}" data-uuid="{{ uuid }}" data-slug="{{ slug }}" data-layout="{{ layout }}">
<div id="post-edit-index-wrapper">
<div id="post-feature">
<section data-index="{{ id }}" data-uuid="{{ uuid }}" data-slug="{{ slug }}" data-layout="{{ layout }}" role="file-manager">
{% if page['feature'] == null %}
<div id="page-file-manager">
<div id="page-file-wrapper">
<div id="page-file-drop">
<div role="file-drop">
<label for="page-files-upload">DRAG AND DROP FILES OR CLICK TO SELECT</label>
</div>
IMAGES AND VIDEO
<div id="page-images-list"></div>
FILES
<div id="page-files-list"></div>
</div>
</div>
<label role="list-title">IMAGES AND VIDEO</label>
<div role="page-images-list"></div>
<label role="list-title">FILES</label>
<div role="page-files-list"></div>
{% else %}
<div id="page-file-manager">
<div id="page-file-wrapper">
<div id="page-file-drop">
<div role="file-drop">
<label for="page-files-upload">DRAG AND DROP FILES OR CLICK TO SELECT</label>
</div>
IMAGES AND VIDEO
<div id="page-images-list">
<label role="list-title">IMAGES AND VIDEO</label>
<div role="page-images-list">
{% if media|length > 1 %}
{% for item in media %}
{% set fileName = item.file|split('/') %}
{% if item.type == "mp4" %}
<div id="{{ loop.index0 }}" class="video-item" data-source="{{ item.file }}" data-file-name="{{ fileName[6] }}">
<button id="{{ loop.index0 }}" class="media-remove">X</button>
<div id="{{ loop.index0 }}" class="video-item" data-source="{{ item.file }}">
<video>
<source src="{{ item.file }}"/>
</video>
<button id="{{ loop.index0 }}" class="media-remove">
<i class="ti ti-x"></i>
</button>
</div>
{% else %}
<div id="{{ loop.index0 }}" class="img-item" style="background: url({{ item.file }}) no-repeat center center / cover" data-file-name="{{ fileName[6] }}">
<button id="{{ loop.index0 }}" class="media-remove">X</button>
<div id="{{ loop.index0 }}" class="img-item" data-source="{{ item.file }}" style="background: url({{ item.file }}) no-repeat center center / cover">
<button id="{{ loop.index0 }}" class="media-remove">
<i class="ti ti-x"></i>
</button>
</div>
{% endif %}
{% endfor %}
@ -82,32 +80,41 @@
{% if media[0] != '' %}
{% set fileName = media[0].file|split('/') %}
{% if media[0].type == "mp4" %}
<div id="0" class="video-item" data-source="{{ media[0].file }}" date-file-name="{{ fileName[6] }}">
<div id="0" class="video-item" data-source="{{ media[0].file }}">
<button id="{{ loop.index0 }}" class="media-remove">X</button>
</div>
{% else %}
<div id="0" class="img-item" style="background: url({{ media[0].file }}) no-repeat center center / cover" data-file-name="{{ fileName[6] }}">
<button id="{{ loop.index0 }}" class="media-remove">X</button>
<div id="0" class="img-item" data-source="{{ media[0].file }}" style="background: url({{ media[0].file }}) no-repeat center center / cover">
<button id="{{ loop.index0 }}" class="media-remove">
<i class="ti ti-x"></i>
</button>
</div>
{% endif %}
{% else %}
{% endif %}
{% endif %}
</div>
FILES
<div id="page-files-list">
<label role="list-title">FILES</label>
<div role="page-files-list">
{% if files|length > 1 %}
{% for item in files %}
{% set fileName = item.file|split('/') %}
{% if item.type == "mp3" %}
<div id="{{ loop.index0 }}" class="audio-item" data-source="{{ item.file }}" data-file-name="{{ fileName[6] }}">
<button id="{{ loop.index0 }}" class="media-remove">X</button>
<div id="{{ loop.index0 }}" class="audio-item" data-source="{{ item.file }}">
<audio controls>
<source src="{{ item.file }}"/>
</audio>
<button id="{{ loop.index0 }}" class="media-remove">
<i class="ti ti-x"></i>
</button>
</div>
{% else %}
<div id="{{ loop.index0 }}" class="file-item" data-source="{{ item.file }}" data-file-name="{{ fileName[6] }}">
<button id="{{ loop.index0 }}" class="media-remove">X</button>
<div id="{{ loop.index0 }}" class="file-item" data-source="{{ item.file }}">
<a href="{{ item.file }}" target="_blank">{{ fileName[6] }}"</a>
<button id="{{ loop.index0 }}" class="media-remove">
<i class="ti ti-x"></i>
</button>
</div>
{% endif %}
{% endfor %}
@ -115,12 +122,20 @@
{% if files[0] != '' %}
{% set fileName = files[0].file|split('/') %}
{% if files[0].type == "mp3" %}
<div id="0" class="audio-item" data-source="{{ files[0].file }}" data-file-name="{{ fileName[6] }}">
<button id="{{ loop.index0 }}" class="media-remove">X</button>
<div id="0" class="audio-item" data-source="{{ files[0].file }}">
<audio controls>
<source src="{{ files[0].file }}"/>
</audio>
<button id="{{ loop.index0 }}" class="media-remove">
<i class="ti ti-x"></i>
</button>
</div>
{% else %}
<div id="0" class="file-item" data-source="{{ files[0].file }}" data-file-name="{{ fileName[6] }}">
<button id="{{ loop.index0 }}" class="media-remove">X</button>
<div id="0" class="file-item" data-source="{{ files[0].file }}">
<a href="{{ item.file }}" target="_blank">{{ fileName[6] }}"</a>
<button id="{{ loop.index0 }}" class="media-remove">
<i class="ti ti-x"></i>
</button>
</div>
{% endif %}
@ -129,21 +144,21 @@
{% endif %}
{% endif %}
</div>
</div>
</div>
{% endif %}
</div>
<div id="post-header">
<div id="post-header-wrapper" class="columns">
<div id="post-edit-title" class="column">
<label>TITLE</label>
</section>
<section role="page-meta">
<div role="page-meta-wrapper">
<div role="page-title">
<strong>TITLE</strong>
<textarea id="post-title-text" type="text" name="post-title-text" class="post-edit" placeholder="TITLE">{{ title }}</textarea>
<div id="layouts">
<label>LAYOUTS</label>
</div>
<div role="page-tags">
<strong>TAGS</strong>
<textarea id="post-tags" type="text" name="post-tags" class="form-control" placeholder="tags [comma seperated]">{{ tags }}</textarea>
</div>
<div role="page-layouts">
<strong>LAYOUTS</strong>
<select id="page-templates">
{% for view in views %}
{% if view == page['layout'] %}
@ -155,44 +170,38 @@
{% endfor %}
</select>
</div>
<label>CREATED</label>
<span id="post-date" type="text">
{{ date }}
</span>
</div>
<div id="post-meta" class="column">
<label>TAGS</label>
<textarea id="post-tags" type="text" name="post-tags" class="form-control" placeholder="tags [comma seperated]">{{ tags }}</textarea>
<label>OPTIONS</label>
<div role="page-options">
<strong>OPTIONS</strong>
{% apply spaceless %}
{{ include("dash/partials/options.twig") }}
{% endapply %}
<label>UPDATED</label>
</div>
<div role="page-updated">
<strong>UPDATED</strong>
<span id="post-date" type="text">
{{ updated }}
</span>
</div>
<div role="page-created">
<strong>CREATED</strong>
<span id="post-date" type="text">
{{ date }}
</span>
<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="form_token" name="token" type="hidden" value="{{ token }}"></div>
</div>
</div>
<div id="edit-post">
</section>
<section role="text-editor">
{% apply spaceless %}
{{ include("dash/partials/editor.twig") }}
{% endapply %}
<div id="edit-post-wrapper">
<div role="edit-post-wrapper">
<textarea id="edit" spellcheck="false">{{ content }}</textarea>
<pre id="highlight">
<code id="highlight-content" class="language-md">
</code>
<code id="highlight-content" class="language-md"></code>
</pre>
</div>
</div>
</div>
</div>
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js?=dfdvbd" type="text/javascript"></script>
</section>
{% endblock %}

View file

@ -1,9 +1,9 @@
<div id="edit-control">
<div role="text-editor-control">
<button id="edit-bold" class="content-editor-btn-text editor-button" title="bold">B</button>
<button id="edit-italic" class="content-editor-btn-text editor-button" title="italic">I</button>
<button id="edit-strikethrough" class="content-editor-btn-text editor-button" title="strikethrough">D</button>
<button id="edit-link" class="content-editor-btn-icon editor-button" title="insert link">
<svg id="edit-link" viewbox="0 0 20 20" class="icons">
<svg id="edit-link" role="icon">
<use id="edit-link" xlink:href="/assets/images/global/sprite.svg#entypo-link"/>
</svg>
</button>
@ -11,35 +11,32 @@
<button id="edit-header2" class="content-editor-btn-text editor-button" title="header 2">H2</button>
<button id="edit-header3" class="content-editor-btn-text editor-button" title="header 3">H3</button>
<button id="edit-image" class="content-editor-btn-icon editor-button" title="insert image">
<svg id="edit-image" viewbox="0 0 20 20" class="icons">
<svg id="edit-image" role="icon">
<use id="edit-image" xlink:href="/assets/images/global/sprite.svg#entypo-image"/>
</svg>
</button>
{% if mode == "edit" %}
<button id="edit-update" class="post-sumbit-btn submit-start editor-button" data-action='blog-update' data-id="{{ page['uuid'] }} type='submit' title=" bold">
<svg id="submit-update" viewbox="0 0 20 20" class="icons">
<svg id="submit-update" role="icon">
<use id="submit-update" xlink:href="/assets/images/global/sprite.svg#entypo-save" data-action='blog-update' data-id="{{ page['uuid'] }}"/>
</svg>
<svg id="submit-good" class="icon-hide" viewbox="0 0 20 20" class="icons">
<svg id="submit-good" class="icon-hide" role="icon">
<use xlink:href="/assets/images/global/sprite.svg#entypo-thumbs-up"/>
</svg>
<svg id="submit-error" class="icon-hide" viewbox="0 0 20 20" class="icons">
<svg id="submit-error" class="icon-hide" role="icon">
<use xlink:href="/assets/images/global/sprite.svg#entypo-thumbs-down"/>
</svg>
</button>
<button id="edit-delete" class="content-editor-btn-icon editor-button submit-delete" for="post-delete" title='delete post'>
<svg id="edit-delete" viewbox="0 0 20 20" class="icons">
<svg id="edit-delete" role="icon">
<use id="edit-delete" xlink:href="/assets/images/global/sprite.svg#entypo-cross"/>
</svg>
</button>
{% else %}
<button id="edit-save" class="post-sumbit-btn submit-start editor-button" data-action='blog-add' type='submit'>
<svg id="submit-save" viewbox="0 0 20 20" class="icons">
<svg id="submit-save" role="icon">
<use id="submit-save" xlink:href="/assets/images/global/sprite.svg#entypo-plus"/>
</svg>
</button>
{% endif %}
</div>

View file

@ -1,8 +1,8 @@
<section role="index-header">
<div>
<div role="index-header-left">
<h1>Recent</h1>
</div>
<div>
<div role="index-header-right">
<a href='/dashboard/pages' title="view pages">
<button>
<svg role="icon">

View file

@ -6,7 +6,6 @@
</svg>
</button>
</a>
.
<a id="navigation" href="/dashboard/navigation" title="edit navigation">
<button>
<svg role="icon">
@ -14,7 +13,6 @@
</svg>
</button>
</a>
.
<a id="navigation" href="/dashboard/logout" title="log out">
<button>
<svg role="icon">

View file

@ -0,0 +1,10 @@
<div role="notify-message">
<div role="notify-icons">
<i class="ti ti-mood-smile" role="notify-good"></i>
<i class="ti ti-mood-sad" role="notify-notgood"></i>
<i class="ti ti-settings" role="notify-working"></i>
</div>
<div role="notify-text">
<span role="response-text">Hey Hey</span>
</div>
</div>

View file

@ -15,28 +15,26 @@
{% else %}
{% set published = 'false' %}
{% endif %}
<div id="post-options">
<br>
<button id="option-menu-pin" class="option-inactive post-option-btn" data-active="{{ menu }}" title='Pin to Menu'>
<svg id="option-page-icon" viewbox="0 0 20 20" class="icons">
<svg id="option-page-icon" role="icon">
<use id="option-page-icon" xlink:href="/assets/images/global/sprite.svg#entypo-add-to-list"/>
</svg>
</button>
<button id="option-feature" class="option-inactive post-option-btn" data-active="{{ featured }}" title='Feature'>
<svg id="option-feature-icon" viewbox="0 0 20 20" class="icons">
<svg id="option-feature-icon" role="icon">
<use id="option-feature-icon" xlink:href="/assets/images/global/sprite.svg#entypo-star"/>
</svg>
</button>
<button id="option-published" class="option-inactive post-option-btn" data-active="{{ published }}" title='Published'>
<svg id="option-published-icon" viewbox="0 0 20 20" class="icons">
<svg id="option-published-icon" role="icon">
<use id="option-published-icon" xlink:href="/assets/images/global/sprite.svg#entypo-globe"/>
</svg>
</button>
<a href="/dashboard/page/preview/{{ uuid }}" target="_blank">
<button id="option-preview" class="option-inactive post-option-btn" data-active="false" title='preview page'>
<svg id="option-preview-icon" viewbox="0 0 20 20" class="icons">
<svg id="option-preview-icon" role="icon">
<use id="option-preview-icon" xlink:href="/assets/images/global/sprite.svg#entypo-eye"/>
</svg>
</button>
</a>
</div>

View file

@ -35,7 +35,3 @@
</div>
</div>
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js" type="text/javascript"></script>
{% endblock %}

View file

@ -172,7 +172,8 @@
<div class="column">
{% if lastBackup != '' %}
<div class="backup-meta">
LAST BACK UP <a href="/api/v1/files">{{lastBackup}}</a><br />
LAST BACK UP
<a href="/api/v1/files">{{ lastBackup }}</a><br/>
</div>
{% else %}
<span>span No back ups. Frowny face.</span>
@ -186,7 +187,3 @@
</div>
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js" type="text/javascript"></script>
{% endblock %}

View file

@ -17,7 +17,3 @@
{{ include("dash/forms/login.twig") }}
{% endif %}
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js?=dfadsf" type="text/javascript"></script>
{% endblock %}

16585
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -7,37 +7,29 @@
"version": "1.0.0",
"description": "The most chill API for the most chill blog framework"
},
"source": "src/com/Start.js",
"main": "public/assets/scripts/start.js",
"targets": {
"main": {
"includeNodeModules": true
}
},
"scripts": {
"watch": "parcel watch",
"build": "parcel build"
},
"devDependencies": {
"@babel/preset-env": "^7.16.5",
"babel-cli": "^6.26.0",
"eslint": "^8.11.0",
"eslint-plugin-babel": "^5.3.1",
"parcel": "^2.0.1",
"prettier": "^2.6.0",
"stylelint": "^14.8.2",
"stylelint-config-prettier-scss": "^0.0.1",
"stylelint-config-standard-scss": "^3.0.0"
"@babel/core": "^7.21.3",
"babel-plugin-prismjs": "^2.1.0",
"parcel": "^2.8.3",
"prettier": "^2.8.4",
"stylelint": "^15.3.0",
"stylelint-config-standard": "^31.0.0"
},
"dependencies": {
"@babel/core": "^7.16.5",
"@babel/eslint-parser": "^7.16.5",
"animejs": "^3.2.1",
"babel-plugin-prismjs": "^2.1.0",
"babel-preset-env": "^1.7.0",
"bulma": "^0.9.3",
"caret-pos": "^2.0.0",
"jsdoc": "^3.6.7",
"minami": "^1.2.3",
"prismjs": "^1.25.0",
"sass": "^1.45.1",
"sortablejs": "^1.14.0"
},
"license": "UNLICENSED",
"author": "Are0h",
"scripts": {
"watch": "npx parcel watch src/com/Start.js --dist-dir public/assets/scripts --public-url /assets/scripts",
"build": "npx parcel build src/com/Start.js --dist-dir public/assets/scripts --public-url /assets/scripts"
},
"description": "Front end script for the most chill blog framework ever.",
"repository": "https://code.playvicio.us/Are0h/Fipamo"
"prismjs": "^1.29.0",
"sortablejs": "^1.15.0"
}
}

View file

@ -1,43 +0,0 @@
{
"name": "fipamo-dash",
"version": "2.5.1-beta",
"private": true,
"apidoc": {
"name": "Fipamo API",
"version": "1.0.0",
"description": "The most chill API for the most chill blog framework"
},
"devDependencies": {
"@babel/preset-env": "^7.16.5",
"babel-cli": "^6.26.0",
"eslint": "^8.11.0",
"eslint-plugin-babel": "^5.3.1",
"parcel": "^2.0.1",
"prettier": "^2.6.0",
"stylelint": "^14.8.2",
"stylelint-config-prettier-scss": "^0.0.1",
"stylelint-config-standard-scss": "^3.0.0"
},
"dependencies": {
"@babel/core": "^7.16.5",
"@babel/eslint-parser": "^7.16.5",
"animejs": "^3.2.1",
"babel-plugin-prismjs": "^2.1.0",
"babel-preset-env": "^1.7.0",
"bulma": "^0.9.3",
"caret-pos": "^2.0.0",
"jsdoc": "^3.6.7",
"minami": "^1.2.3",
"prismjs": "^1.25.0",
"sass": "^1.45.1",
"sortablejs": "^1.14.0"
},
"license": "UNLICENSED",
"author": "Are0h",
"scripts": {
"watch": "sass --watch src/styles:public/assets/css & npx parcel watch src/com/Start.js --dist-dir public/assets/scripts --public-url /assets/scripts",
"build": "sass src/styles:public/assets/css & npx parcel build src/com/Start.js --dist-dir public/assets/scripts --public-url /assets/scripts"
},
"description": "Front end script for the most chill blog framework ever.",
"repository": "https://code.playvicio.us/Are0h/Fipamo"
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,22 @@
:root {
/* BASE COLORS */
--primary: #1d3040;
--secondary: #b2cce5;
--tertiary: #f5ab35;
--highlight: #fc6399;
--white: #efebe3;
--grey: #abb7b7;
--black: #32302f;
/* EDITOR COLORS */
--event-cool: #32cd32;
--event-lame: #f64747;
--editor-primary: #fde3a7;
--editor-secondary: #e7903c;
--editor-tertiary: #6bb9f0;
--editor-string: #dcc6e0;
--editor-tag: #e73c4e;
/* RGB Versions */
--primary-rgb: 29 28 24;
}

View file

@ -0,0 +1,54 @@
a {
color: var(--primary);
}
p {
background: var(--tertiary);
color: var(--primary);
padding: 5px;
display: block;
border-radius: 5px;
text-align: left;
}
input[type="email"],
input[type="password"],
input[type="text"] {
border: 0;
border-radius: 5px;
font: 18px var(--base-type);
display: inline-block;
background: var(--primary);
color: var(--tertiary);
}
textarea {
border: 0;
border-radius: 3px;
color: var(--white);
background: var(--primary);
}
button,
input[type="submit"] {
background: var(--highlight);
color: var(--primary);
font: 20px var(--base-type);
border-radius: 5px;
position: relative;
cursor: pointer;
border: 0;
transition: all 0.3s linear;
}
select {
font: 14px var(--base-type);
border: 1px solid var(--secondary);
appearance: none;
color: var(--primary);
}
::placeholder {
font: 25px var(--base-type);
color: var(--white);
}

View file

@ -0,0 +1,131 @@
html {
width: 100%;
height: 100%;
overflow: hidden;
font: 400 1.2em/1.4em var(--base-type);
}
html body {
background: var(--primary);
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow-y: scroll;
overflow-x: hidden;
}
/* GLOBALS */
a {
color: var(--primary);
text-decoration: none;
border-bottom: 1px solid var(--secondary);
transition: all 0.2s linear;
}
a:hover {
border-bottom: 1px solid var(--highlight);
}
sup {
background: var(--black);
color: var(--white);
padding: 3px;
border-radius: 3px;
}
#notifications {
display: none;
visibility: hidden;
}
pre,
code {
background: var(--black);
color: var(--highlight);
border-radius: 3px;
padding: 3px;
}
svg[role="icon"] {
fill: var(--white);
width: 25px;
height: 25px;
padding-top: 5px;
}
/* HEADER
Navigation
Notificiations
*/
header {
width: 100%;
max-width: 900px;
margin: 10px auto;
background: var(--white);
height: 50px;
border-radius: 5px;
left: 50%;
transform: translate(-50%, 0);
position: fixed;
z-index: 500;
box-shadow: 2px 2px 0 rgba(var(--primary-rgb) / 30%);
}
header > nav {
display: grid;
grid-template-columns: 50px 1fr auto;
}
header > nav > div[role="nav-left"] img {
width: 40px;
padding: 5px;
}
header > nav > div[role="nav-right"] {
padding: 5px;
}
header > nav > div[role="nav-right"] button {
width: 40px;
height: 40px;
margin-left: 5px;
}
section[role="login"] {
margin: 15% auto;
padding: 10px;
width: 500px;
border-radius: 5px;
background: var(--white);
display: grid;
grid-template-columns: 28.5% 1fr;
gap: 10px;
}
section[role="login"] form input {
width: 95%;
height: 30px;
padding: 5px;
margin-bottom: 10px;
}
section[role="login"] form button {
padding: 10px 5px;
width: 82%;
}
section[role="login"] form a {
padding: 10px 5px;
border-radius: 5px;
width: 10%;
height: 20px;
display: inline-block;
background: var(--tertiary);
vertical-align: top;
text-align: center;
margin: 0 0 0 10px;
font-weight: 600;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,85 @@
section[role="index-header"] {
display: grid;
grid-template-columns: 1fr 1fr;
width: 100%;
max-width: 900px;
margin: 60px auto 0;
}
section[role="index-recent-pages"] a {
width: 100%;
height: 100%;
display: flex;
justify-content: left;
align-items: center;
border-radius: 5px;
border-bottom: none;
}
section[role="index-recent-pages"] a:nth-child(1) {
grid-column: 1/4;
grid-row: 1/3;
}
section[role="index-recent-pages"] a:nth-child(2) {
grid-row: 3/6;
}
section[role="index-recent-pages"] a:nth-child(3) {
grid-column: 2/4;
grid-row: 3/5;
}
section[role="index-header"] div[role="index-header-right"] {
display: flex;
justify-content: right;
align-items: center;
}
section[role="index-header"] div[role="index-header-right"] a {
border-bottom: none;
margin-left: 5px;
}
section[role="index-recent-pages"] {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: minmax(200px, auto);
gap: 10px;
width: 100%;
max-width: 900px;
margin: 10px auto;
}
section[role="index-recent-pages"] a button {
padding: 1px 5px;
}
section[role="index-recent-pages"] button[data-active="true"] {
background: var(--primary);
}
section[role="index-recent-pages"] button[data-active="true"] svg {
fill: var(--tertiary);
}
section[role="index-recent-pages"] button[data-active="false"] {
background: var(--secondary);
}
section[role="index-recent-pages"] button[data-active="false"] svg {
fill: var(--primary);
}
section[role="index-recent-pages"] aside {
font-size: 1.1em;
color: var(--white);
text-shadow: 2px 2px 2px var(--black);
padding: 10px;
}
section[role="index-recent-pages"] hr {
color: var(--white);
border: 0.1px solid;
margin: 7px 0;
}

View file

@ -0,0 +1,66 @@
header > nav > div[role="notifications"] {
width: 100%;
}
header > nav > div[role="notifications"] > div[role="notify-message"] {
display: flex;
height: 86%;
}
header > nav > div[role="notifications"] > div[role="notify-message"] div {
display: inline-block;
transition: all 0.2s linear;
}
header
> nav
> div[role="notifications"]
> div[role="notify-message"]
> div[role="notify-text"] {
color: var(--white);
border-radius: 5px;
height: 79%;
margin-top: 5px;
opacity: 0;
}
header
> nav
> div[role="notifications"]
> div[role="notify-message"]
> div[role="notify-icons"] {
margin: 5px;
width: 0;
opacity: 0;
}
header
> nav
> div[role="notifications"]
> div[role="notify-message"]
> div[role="notify-text"]
span {
display: block;
padding: 5px;
margin-top: 4px;
}
header > nav > div[role="notifications"] > div[role="notify-message"] i {
display: none;
color: var(--primary);
}
i[role="notify-working"] {
animation: 2s infinite linear spin;
height: 40px;
width: 40px;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View file

@ -0,0 +1,111 @@
code[class*="language-"],
pre[class*="language-"] {
color: var(--editor-primary);
background: none;
font-family: var(--mono-type);
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
tab-size: 4;
hyphens: none;
}
pre[class*="language-"] {
margin: 0.1em 0;
overflow: auto;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: var(--primary);
}
:not(pre) {
& > code[class*="language-"] {
padding: 0.1em;
border-radius: 0.3em;
white-space: normal;
}
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #8292a2;
}
.token.punctuation {
color: var(--editor-secondary);
}
.token.namespace {
opacity: 0.6;
}
.token.keyword {
color: #66d9ef;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.token.content {
color: var(--editor-tertiary);
}
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted {
color: var(--editor-tag);
}
.token.boolean,
.token.number {
color: #ae81ff;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #a6e22e;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: var(--editor-string);
}
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name {
color: #e6db74;
}
.token.regex,
.token.important {
color: var(--editor-secondary);
}
.token.important,
.token.bold {
font-weight: normal;
}

View file

@ -0,0 +1,345 @@
/* FILE MANAGER */
main > section[role="file-manager"] {
width: 100%;
background: var(--tertiary);
padding: 20px 0;
margin-top: 75px;
}
main > section[role="file-manager"] label[role="list-title"] {
width: 100%;
max-width: 900px;
margin: 0 auto;
display: block;
color: var(--primary);
}
main > section[role="file-manager"] > div[role="file-drop"] {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 100px;
background: var(--white);
color: var(--primary);
vertical-align: middle;
border-radius: 5px;
max-width: 900px;
margin: 10px auto;
}
main > section[role="file-manager"] > div[role="page-images-list"],
main > section[role="file-manager"] > div[role="page-files-list"] {
max-width: 900px;
width: 100%;
margin: 10px auto;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
gap: 10px;
}
main > section[role="file-manager"] > div[role="page-images-list"] > div,
main > section[role="file-manager"] > div[role="page-files-list"] > div {
width: 100%;
height: 150px;
border-radius: 3px;
overflow: hidden;
position: relative;
cursor: pointer;
}
main
> section[role="file-manager"]
> div[role="page-images-list"]
> div
> div.item-progress {
width: 100%;
height: 100%;
background: var(--primary);
}
main
> section[role="file-manager"]
> div[role="page-images-list"]
> div
> button.media-remove,
main
> section[role="file-manager"]
> div[role="page-files-list"]
> div
> button.media-remove {
color: var(--white);
margin: 5px;
}
main
> section[role="file-manager"]
> div[role="page-images-list"]
> div.video-item
> video {
object-fit: cover;
height: 100%;
width: 100%;
}
main
> section[role="file-manager"]
> div[role="page-images-list"]
> div.video-item
> button,
main
> section[role="file-manager"]
> div[role="page-files-list"]
> div.audio-item
> button,
main
> section[role="file-manager"]
> div[role="page-files-list"]
> div.file-item
> button {
position: absolute;
top: 0;
left: 0;
}
main
> section[role="file-manager"]
> div[role="page-files-list"]
> div.audio-item {
background: url("/assets/images/global/upload-audio.png") no-repeat center
center / cover;
}
main
> section[role="file-manager"]
> div[role="page-files-list"]
> div.file-item {
background: url("/assets/images/global/upload-doc.png") no-repeat center
center / cover;
}
main
> section[role="file-manager"]
> div[role="page-files-list"]
> div.file-item
> a {
position: absolute;
bottom: 0;
background: var(--secondary);
padding: 2px;
}
main
> section[role="file-manager"]
> div[role="page-files-list"]
> div.audio-item
> audio {
height: 100%;
width: 100%;
}
/* PAGE META */
main > section[role="page-meta"] {
width: 100%;
background: var(--highlight);
}
main > section[role="page-meta"] > div[role="page-meta-wrapper"] {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
width: 100%;
max-width: 900px;
margin: 10px auto;
color: var(--white);
}
main section[role="page-meta"] textarea#post-title-text {
background: var(--white);
font-family: var(--base-type);
width: 100%;
height: 80px;
font-size: 2em;
color: var(--primary);
}
main section[role="page-meta"] textarea#post-tags {
background: var(--white);
font-family: var(--base-type);
width: 100%;
height: 80px;
color: var(--primary);
}
main section[role="page-meta"] select {
background: var(--primary);
color: var(--secondary);
border-radius: 3px;
border-color: var(--primary);
width: 100%;
height: 45px;
padding: 5px;
font-size: 1.5em;
}
main section[role="page-meta"] div[role="page-options"] {
width: 100%;
}
main
section[role="page-meta"]
div[role="page-meta-wrapper"]
div[role="page-options"]
button {
width: 25%;
height: 45px;
transition: all 0.3s linear;
margin: 0;
border-radius: 0;
display: inline-block;
vertical-align: top;
text-align: center;
}
main
> section[role="page-meta"]
> div[role="page-meta-wrapper"]
> div[role="page-options"]
> button.post-option-btn:nth-child(3) {
border-radius: 3px 0 0 3px;
}
main
> section[role="page-meta"]
> div[role="page-meta-wrapper"]
> div[role="page-options"]
> a
> button {
border-radius: 0 3px 3px 0;
}
main
section[role="page-meta"]
div[role="page-meta-wrapper"]
button[data-active="false"] {
background: var(--primary);
}
main
section[role="page-meta"]
div[role="page-meta-wrapper"]
button[data-active="false"]
svg {
fill: var(--secondary);
}
main
section[role="page-meta"]
div[role="page-meta-wrapper"]
div[role="page-options"]
button[data-active="true"] {
background: var(--tertiary);
}
main
section[role="page-meta"]
div[role="page-meta-wrapper"]
div[role="page-options"]
button[data-active="true"]
svg {
fill: var(--primary);
}
main
section[role="page-meta"]
div[role="page-meta-wrapper"]
div[role="page-created"]
input {
display: none;
visibility: hidden;
}
/* TEXT EDITOR */
main > section[role="text-editor"] {
width: 100%;
max-width: 900px;
margin: 0 auto;
}
main section[role="text-editor"] .icon-hide {
display: none;
visibility: hidden;
}
main > section[role="text-editor"] > div[role="text-editor-control"] {
display: grid;
grid-template-columns: repeat(10, 1fr);
gap: 5px;
}
main > section[role="text-editor"] > div[role="edit-post-wrapper"] {
width: 100%;
max-width: 900px;
border-radius: 5px;
position: relative;
margin: 10px 0;
}
main
> section[role="text-editor"]
> div[role="edit-post-wrapper"]
textarea:focus {
outline: none;
border-color: var(--highlight);
}
main section[role="text-editor"] div[role="edit-post-wrapper"] #edit,
main section[role="text-editor"] div[role="edit-post-wrapper"] #highlight {
font-family: var(--mono-type);
border: 0;
width: 100%;
min-height: 300px;
height: auto;
position: absolute;
top: 0;
left: 0;
overflow: auto;
word-wrap: normal;
white-space: pre-wrap;
line-break: normal;
font-size: 1.1em;
line-height: 1.2;
padding: 0;
margin: 0;
}
main
section[role="text-editor"]
div[role="edit-post-wrapper"]
#highlight-content {
word-wrap: normal;
white-space: pre-wrap;
line-break: normal;
}
main > section[role="text-editor"] > div[role="edit-post-wrapper"] > #edit {
z-index: 1;
background: transparent;
color: transparent;
caret-color: var(--highlight);
}
main
> section[role="text-editor"]
> div[role="edit-post-wrapper"]
> #highlight {
z-index: 0;
}
main section[role="text-editor"] div[role="edit-post-wrapper"] pre,
main section[role="text-editor"] div[role="edit-post-wrapper"] pre code {
padding: 0;
margin: 0;
}

View file

@ -0,0 +1,9 @@
@import url("colors.css");
@import url("forms.css");
@import url("typography.css");
@import url("frame.css");
@import url("icons.css");
@import url("notifications.css");
@import url("index.css");
@import url("page-editor.css");
@import url("page-editor-highlights.css");

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,29 @@
:root {
--base-type: helvetica, arial, sans-serif;
--mono-type: "Lucida Console", monaco, monospace;
}
h1,
h2,
h3 {
color: var(--white);
}
h1 {
font-size: 2em;
font-weight: 700;
}
h2 {
font-size: 1.8em;
font-weight: 600;
}
h3 {
font-size: 1.5em;
font-weight: 500;
}
main > article > h1 {
color: var(--primary);
}

File diff suppressed because it is too large Load diff

View file

@ -57,7 +57,7 @@ export default class Base {
let self = this;
e.preventDefault();
let authForm = data.formDataToJSON(document.getElementById('login'));
notify.alert('Looking, hold up', null);
//notify.alert('Looking, hold up', null);
let api = new FipamoAdminAPI();
this.processing = true;
api.login(authForm)
@ -66,7 +66,7 @@ export default class Base {
if (response.type === DataEvent.REQUEST_LAME) {
notify.alert(response.message, false);
} else {
notify.alert(response.message, true);
//notify.alert(response.message, true);
e.target.innerHTML = response.message;
setTimeout(() => {
window.location = '/dashboard';

View file

@ -9,84 +9,41 @@ export default class PostActions {
//--------------------------
collectInfo(files) {
return new Promise((resolve, reject) => {
let pageInfo = new FormData();
pageInfo.enctype = 'multipart/form-data';
let pageInfo = [];
let pageRef = document.querySelector('[role="file-manager"]');
//process html content for storage
let txt = document.createElement('textarea');
txt.innerHTML = document.getElementById('highlight-content').innerHTML;
let html = txt.value;
html = html.replace(/<\/?span[^>]*>/g, ''); //removes prism styling
html = html.replace(/<\/?br[^>]*>/g, '\n'); //convert back to encoded line break for storage
pageInfo.append(
'id',
document.getElementById('post-edit-index').getAttribute('data-index')
);
pageInfo.append(
'uuid',
document.getElementById('post-edit-index').getAttribute('data-uuid')
);
pageInfo.append(
'layout',
document.getElementById('post-edit-index').getAttribute('data-layout')
);
pageInfo.append(
'current_title',
document.getElementById('post-edit-index').getAttribute('data-slug')
);
pageInfo.append('content', html);
pageInfo.append('title', document.getElementById('post-title-text').value);
pageInfo.append(
'created',
document.getElementById('post-date').getAttribute('data-raw')
);
pageInfo.append(
'slug',
new StringUtils().cleanString(
//build data object
pageInfo = {
id: pageRef.getAttribute('data-index'),
uuid: pageRef.getAttribute('data-uuid'),
layout: document.getElementById('page-templates').value,
current_title: pageRef.getAttribute('data-slug'),
content: html,
title: document.getElementById('post-title-text').value,
created: document.getElementById('post-date').getAttribute('data-raw'),
slug: new StringUtils().cleanString(
document.getElementById('post-title-text').value
)
);
pageInfo.append('tags', document.getElementById('post-tags').value);
pageInfo.append(
'menu',
document.getElementById('option-menu-pin').getAttribute('data-active')
);
pageInfo.append(
'featured',
document.getElementById('option-feature').getAttribute('data-active')
);
pageInfo.append(
'published',
document.getElementById('option-published').getAttribute('data-active')
);
pageInfo.append('layout', document.getElementById('page-templates').value);
pageInfo.append('form_token', document.getElementById('form_token').value);
if (files.length > 0 && files != null) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (
file.type.match('image.*') ||
file.type.match('video.mp4') ||
file.type.match('audio.mpeg') ||
file.type.match('application.pdf') ||
file.type.match('text.plain') ||
file.type.match('text.rtf')
) {
pageInfo.append('page_files[]', file, file.name);
} else {
reject('Not an image file: ' + file.type);
}
}
} else {
//check to see if image exists
if (document.getElementById('featured-image')) {
var imageURL = document.getElementById('featured-image').src;
imageURL != null || imageURL != undefined
? pageInfo.append('feature_image', imageURL)
: pageInfo.append('feature_image', null);
} else {
//pageInfo.append("feature_image", null);
}
}
//console.log("FILES", files);
),
tags: document.getElementById('post-tags').value,
menu: document
.getElementById('option-menu-pin')
.getAttribute('data-active'),
featured: document
.getElementById('option-feature')
.getAttribute('data-active'),
published: document
.getElementById('option-published')
.getAttribute('data-active'),
form_token: document.getElementById('form_token').value,
imageList: files.images,
fileList: files.files
};
resolve(pageInfo);
});
}

View file

@ -18,6 +18,7 @@ export const API_RESTORE_BACKUP = '/api/v1/backup/restore';
export const API_UPLOAD_AVATAR = '/api/v1/settings/add-avatar';
export const API_UPLOAD_BACKGROUND = '/api/v1/settings/add-feature-background';
export const API_IMAGE_UPLOAD = '/api/v1/page/add-entry-image';
export const API_FILES_UPLOAD = '/api/v1/files';
//** API TASKS **//
export const TASK_SITE_INIT = 'blogInit';
export const TASK_BACKUP_RESTORE = 'restoreBackup';
@ -38,11 +39,21 @@ class MaintenanceManager {
* @param {string} baseURL - url of site; uses local when empty
* @param {string} key - user api key
*/
constructor(baseURL = null, key = null, progressBar = null) {
constructor(baseURL = null, key = null) {
this.accetableFiles = [
'image/jpeg',
'image/gif',
'image/png',
'image/svg',
'audio/mpeg',
'video/mp4',
'application/pdf',
'text/plain',
'text/rtf'
];
this.percentComplete = 0; //for later
this.token = null;
this.baseURL = null;
this.progressBar = progressBar;
this.key = null;
if (key) this.key = key;
if (baseURL) this.baseURL = baseURL;
@ -185,53 +196,28 @@ class MaintenanceManager {
}
/**
* Promise method for uploading images [todo: change to uploading files]
* Promise method for uploading files [todo: change to uploading files]
* @param {string} type - type of upload
* @param {input} files - form input containing files
*/
imageUpload(type, files) {
filesUpload(type, files, progress = null) {
return new Promise((resolve, reject) => {
let url = '';
switch (type) {
case 'avatar-upload':
url = API_UPLOAD_AVATAR;
break;
case 'background-upload':
url = API_UPLOAD_BACKGROUND;
break;
default:
url = API_IMAGE_UPLOAD;
break;
}
var imageData = new FormData();
let url = API_FILES_UPLOAD;
if (this.baseURL) {
imageData.append('key', this.key);
imageData.append('remote', true);
files.append('key', this.key);
files.append('remote', true);
} else {
imageData.append('remote', false);
files.append('remote', false);
}
for (var i = 0; i < files.length; i++) {
var file = files[i];
// Check the file type.
if (!file.type.match('image.*')) {
continue;
}
if (type === 'avatar-upload') {
imageData.append('avatar_upload', file, file.name);
} else if (type === 'background-upload') {
imageData.append('background_upload', file, file.name);
} else {
imageData.append('post_image', file, file.name);
}
}
this._request(
url,
progress,
TASK_UPLOAD_FILES,
REQUEST_TYPE_POST,
CONTENT_TYPE_FORM,
imageData
files
)
.then(r => {
resolve(r);
@ -247,6 +233,7 @@ class MaintenanceManager {
//--------------------------
_request(
requestURL,
progressBar = null,
eventType,
requestType = REQUEST_TYPE_GET,
contentType = CONTENT_TYPE_JSON,
@ -255,8 +242,9 @@ class MaintenanceManager {
var self = this;
return new Promise(function (resolve, reject) {
var request = new XMLHttpRequest();
request.upload.addEventListener('progress', e =>
self.handleLoadProgress(e, self.progressBar)
self.handleLoadProgress(e, progressBar)
);
request.open(requestType, requestURL, true);
request.onload = () => {

View file

@ -21,30 +21,30 @@ export default class PostEditor {
this.processing = false;
let self = 'this';
this.admin = new FipamoAdminAPI(null, document.getElementById('notify-progress'));
this.mm = new Maintenance(null, null, document.getElementById('notify-progress'));
this.mm = new Maintenance(null, null);
this.urlPieces = document.URL.split('/');
this.post = [];
this.postID = null;
this.postUUID = null;
this.postLayout = null;
this.fm = null;
if (document.getElementById('post-edit-index').getAttribute('data-index')) {
if (document.querySelector('[role="file-manager"]').getAttribute('data-index')) {
this.postID = document
.getElementById('post-edit-index')
.querySelector('[role="file-manager"]')
.getAttribute('data-index');
this.postUUID = document
.getElementById('post-edit-index')
.querySelector('[role="file-manager"]')
.getAttribute('data-uuid');
this.postLayout = document
.getElementById('post-edit-index')
.querySelector('[role="file-manager"]')
.getAttribute('data-layout');
}
if (document.getElementById('edit')) {
this.editor = new TextEditor(
document.getElementById('edit'),
document.getElementById('header').offsetHeight +
document.getElementById('post-header').offsetHeight +
document.getElementById('post-feature').offsetHeight
document.querySelector('[role="file-manager"]').offsetHeight +
document.querySelector('[role="page-meta"]').offsetHeight +
document.querySelector('[role="text-editor"]').offsetHeight
);
this.editor.addListener(
EditorEvent.EDITOR_DELETE,
@ -89,13 +89,13 @@ export default class PostEditor {
// methods
//--------------------------
start() {
if (document.getElementById('page-file-drop')) {
if (document.querySelector('[role="file-drop"]')) {
//insert fileManager here
this.fm = new FileManager(
document.getElementById('page-file-drop'),
document.querySelector('[role="file-drop"]'),
document.getElementById('page-files-upload'),
document.getElementById('page-images-list'),
document.getElementById('page-files-list')
document.querySelector('[role="page-images-list"]'),
document.querySelector('[role="page-files-list"]')
);
var optionButtons = document.querySelectorAll('.post-option-btn');
for (var i = 0, length = optionButtons.length; i < length; i++) {
@ -143,8 +143,7 @@ export default class PostEditor {
e === EditorEvent.EDITOR_SAVE
? (task = TASK_PAGE_CREATE)
: (task = TASK_PAGE_EDIT);
new PageActions().collectInfo(this.fm.getFiles()).then(page => {
new PageActions().collectInfo(this.fm.getFileOrder()).then(page => {
self.processing = true;
notify.alert('Writing down changes', null);
self.admin
@ -208,12 +207,18 @@ export default class PostEditor {
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);
let upload = new FormData();
upload.enctype = 'multipart/form-data';
upload.append('upload_files[]', files[0], files[0].name);
this.mm
.filesUpload(files[0].type, upload)
.then(result => {
console.log('RESULT'.result);
if (result.message == 'File Uploaded. Great!') {
self.editor.notify(
EditorEvent.EDITOR_UPLOAD_POST_IMAGE,
result.filePath
);
notify.alert('Image Added to Entry', true);
} else {
notify.alert('Uh oh. Image not added', false);
@ -221,8 +226,6 @@ export default class PostEditor {
})
.catch(() => {
notify.alert('Uh oh. Image not added', false);
//console.log('ERROR', err);
});
}
}
PostEditor.uploadFiles = [];

View file

@ -1,6 +1,8 @@
import Sortable from 'sortablejs';
import anime from 'animejs/lib/anime.es.js';
import DataUtils from '../utils/DataUtils';
import Notfications from './Notifications.js';
import Maintenance from '../controllers/MaintenanceManager';
const notify = new Notfications();
export default class FileManager {
@ -8,6 +10,7 @@ export default class FileManager {
// constructor
//--------------------------
constructor(upload, input, imageList, fileList) {
this.mm = new Maintenance(null, null, document.getElementById('notify-progress'));
this.upload = upload;
this.input = input;
this.imageList = imageList;
@ -29,15 +32,15 @@ export default class FileManager {
this.mediaSort = Sortable.create(this.imageList, {
animation: 150,
onUpdate: () => {
notify.alert('REINDEXING MEDIA', null);
this.updateFiles();
//notify.alert('REINDEXING MEDIA', null);
//this.updateFiles();
}
});
this.fileSort = Sortable.create(this.fileList, {
animation: 150,
onUpdate: () => {
notify.alert('REINDEXING FILES', null);
this.updateFiles();
//notify.alert('REINDEXING FILES', null);
//this.updateFiles();
}
});
this.start();
@ -58,25 +61,19 @@ export default class FileManager {
);
}
}
getFiles() {
return this.files;
getFileOrder() {
let imgList = '';
let fileList = '';
for (var i = 0, length = this.imageList.childNodes.length; i < length; i++) {
let div = this.imageList.childNodes[i];
imgList = imgList + div.getAttribute('data-source') + ',';
}
reindexFiles(sortOrder, step) {
let count = sortOrder.length;
if (step == 0) this.files = [];
var utils = new DataUtils();
utils.imgLoad(sortOrder[step].earl).then(blob => {
var fresh = new File([blob], sortOrder[step].fileName, { type: blob.type });
this.files.push(fresh);
var limit = count - 1;
if (this.files.length <= limit) {
step = step + 1;
this.reindexFiles(sortOrder, step);
} else {
notify.alert('FILES READY TO UPLOAD', true);
for (var i = 0, length = this.fileList.childNodes.length; i < length; i++) {
let div = this.fileList.childNodes[i];
fileList = fileList + div.getAttribute('data-source') + ',';
}
});
let media = { images: imgList, files: fileList };
return media;
}
sortFiles(files) {
@ -88,16 +85,24 @@ export default class FileManager {
return function (f) {
//create remove button object
var remove = document.createElement('button');
var removeIcon = document.createElement('i');
removeIcon.classList.add('ti', 'ti-x');
remove.className = 'media-remove';
remove.innerHTML = 'X';
remove.appendChild(removeIcon);
//remove.setAttribute('id', mediaCount);
remove.addEventListener(
'click',
e => self.removeFile(e, 'media'),
false
);
//get counts for lists
var mediaCount = self.imageList.childNodes.length;
var fileCount = self.fileList.childNodes.length;
//upload the file
let upload = new FormData();
upload.enctype = 'multipart/form-data';
upload.append('upload_files[]', theFile, theFile.name);
let item = null;
let progress = null;
// sort files
switch (theFile.type) {
case 'image/jpg':
@ -105,66 +110,109 @@ export default class FileManager {
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 =
item = self.itemFactory('img-item');
progress = document.getElementById(
'pgs' + item.getAttribute('id')
);
self.mm
.filesUpload(theFile.type, upload, progress)
.then(result => {
item.setAttribute('data-source', result.filePath);
item.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)
anime({
targets: progress,
width: 0,
easing: 'easeInOutQuint',
duration: 1000,
complete: () => {
item.removeChild(progress);
item.appendChild(remove);
}
]);
if (mediaCount < 0) mediaCount = 0;
span.setAttribute('id', mediaCount);
remove.setAttribute('id', mediaCount);
span.setAttribute('data-file-name', theFile.name);
span.appendChild(remove);
self.imageList.appendChild(span);
});
});
break;
case 'video/mp4':
var video = document.createElement('div');
video.className = 'video-item';
video.setAttribute('data-source', f.target.result);
if (mediaCount < 0) mediaCount = 0;
video.setAttribute('id', mediaCount);
remove.setAttribute('id', mediaCount);
video.setAttribute('data-file-name', theFile.name);
video.appendChild(remove);
self.imageList.appendChild(video);
item = self.itemFactory('video-item');
progress = document.getElementById(
'pgs' + item.getAttribute('id')
);
self.mm
.filesUpload(theFile.type, upload, progress)
.then(result => {
item.setAttribute('data-source', result.filePath);
let video = document.createElement('video');
let source = document.createElement('source');
source.src = f.target.result;
video.appendChild(source);
item.appendChild(video);
anime({
targets: progress,
width: 0,
easing: 'easeInOutQuint',
duration: 1000,
complete: () => {
item.removeChild(progress);
item.appendChild(remove);
}
});
});
break;
case 'audio/mpeg':
var sound = document.createElement('div');
sound.className = 'audio-item';
sound.setAttribute('data-source', f.target.result);
sound.setAttribute('id', fileCount);
remove.setAttribute('id', fileCount);
sound.setAttribute('data-file-name', theFile.name);
sound.appendChild(remove);
self.fileList.appendChild(sound);
item = self.itemFactory('audio-item');
progress = document.getElementById(
'pgs' + item.getAttribute('id')
);
self.mm
.filesUpload(theFile.type, upload, progress)
.then(result => {
item.setAttribute('data-source', result.filePath);
let audio = document.createElement('audio');
audio.setAttribute('controls', true);
let source = document.createElement('source');
source.src = f.target.result;
audio.appendChild(source);
item.appendChild(audio);
anime({
targets: progress,
width: 0,
easing: 'easeInOutQuint',
duration: 1000,
complete: () => {
item.removeChild(progress);
item.appendChild(remove);
}
});
});
break;
case 'application/pdf':
case 'text/plain':
case 'text/rtf':
var file = document.createElement('div');
file.className = 'file-item';
file.setAttribute('data-source', f.target.result);
file.setAttribute('id', fileCount);
remove.setAttribute('id', fileCount);
file.setAttribute('data-file-name', theFile.name);
file.appendChild(remove);
self.fileList.appendChild(file);
item = self.itemFactory('file-item');
progress = document.getElementById(
'pgs' + item.getAttribute('id')
);
self.mm
.filesUpload(theFile.type, upload, progress)
.then(result => {
item.setAttribute('data-source', result.filePath);
let link = document.createElement('a');
link.href = result.filePath;
link.innerHTML = result.fileName;
item.appendChild(link);
anime({
targets: progress,
width: 0,
easing: 'easeInOutQuint',
duration: 1000,
complete: () => {
item.removeChild(progress);
item.appendChild(remove);
}
});
});
break;
}
};
@ -172,43 +220,34 @@ export default class FileManager {
// Read in the image file as a data URL.
reader.readAsDataURL(file);
}
//give the script a beat to add the child nodes, then update it all
setTimeout(() => {
self.updateFiles();
}, 50);
}
itemFactory(type = null) {
//get counts for lists
var mediaCount = this.imageList.childNodes.length;
var fileCount = this.fileList.childNodes.length;
if (mediaCount < 0) mediaCount = 0;
if (fileCount < 0) fileCount = 0;
var item = document.createElement('div');
item.className = type;
var progress = document.createElement('div');
progress.className = 'item-progress';
item.appendChild(progress);
if (type == 'img-item' || type == 'video-item') {
this.imageList.appendChild(item);
progress.setAttribute('id', 'pgs' + mediaCount);
item.setAttribute('id', mediaCount);
} else {
this.fileList.appendChild(item);
progress.setAttribute('id', 'pgs' + fileCount);
item.setAttribute('id', fileCount);
}
return item;
}
//--------------------------
// event handlers
//--------------------------
updateFiles() {
let currentFiles = []; //store current list
let items = [];
//get files from media and files list
for (let index = 0; index < this.imageList.childNodes.length; index++) {
items.push(this.imageList.childNodes[index]);
}
for (let index = 0; index < this.fileList.childNodes.length; index++) {
items.push(this.fileList.childNodes[index]);
}
for (let index = 0; index < items.length; index++) {
var item = items[index];
let url = '';
if (item.className == 'img-item') {
url = item.style.backgroundImage.slice(4, -1).replace(/"/g, '');
} else {
url = item.getAttribute('data-source');
}
currentFiles.push({
earl: url,
fileName: item.getAttribute('data-file-name')
});
}
this.reindexFiles(currentFiles, 0);
}
removeFile(e) {
var list = [];
switch (e.target.parentNode.className) {
@ -227,7 +266,7 @@ export default class FileManager {
if (media.id == e.target.id) {
list.removeChild(media);
notify.alert('REINDEXING MEDIA', null);
this.updateFiles();
//this.updateFiles();
}
}
}

View file

@ -1,12 +1,13 @@
import anime from 'animejs/lib/anime.es.js';
const notifcation = document.getElementById('notifications');
const notifcation = document.querySelector('[role="notify-message"]');
const notify = document.getElementById('notify-message');
const messageText = document.getElementById('message-text');
const notifyText = document.getElementById('notify-text');
const notifyProgress = document.getElementById('notify-progress');
const iconGood = document.getElementById('notify-good');
const iconLame = document.getElementById('notify-lame');
const iconWorking = document.getElementById('notify-working');
const responseText = document.querySelector('[role="response-text"]');
const notifyText = document.querySelector('[role="notify-text"]');
const notifyIcons = document.querySelector('[role="notify-icons"]');
//const notifyProgress = document.getElementById('notify-progress');
const iconGood = document.querySelector('[role="notify-good"]');
const iconNotGood = document.querySelector('[role="notify-notgood"]');
const iconWorking = document.querySelector('[role="notify-working"]');
export default class Notfications {
//--------------------------
@ -20,16 +21,10 @@ export default class Notfications {
alert(text, status) {
iconWorking.style.display = 'none';
iconGood.style.display = 'none';
iconLame.style.display = 'none';
iconNotGood.style.display = 'none';
var color = '';
if (status !== null) {
anime({
targets: notifyProgress,
opacity: 0,
easing: 'easeInOutQuint',
duration: 500
});
if (status) {
color = '#32cd32';
iconWorking.style.display = 'none';
@ -37,60 +32,46 @@ export default class Notfications {
} else {
color = '#F64747';
iconWorking.style.display = 'none';
iconLame.style.display = 'block';
iconNotGood.style.display = 'block';
}
} else {
color = '#200317';
iconWorking.style.display = 'block';
anime({
targets: notifyProgress,
opacity: 1,
easing: 'easeInOutQuint',
duration: 500
});
}
messageText.innerHTML = text;
responseText.innerHTML = text;
anime({
targets: notifcation,
marginTop: '-10',
easing: 'easeInOutQuint',
duration: 10,
complete: () => {
anime({
targets: notify,
rotateX: '0',
easing: 'easeInOutQuint',
duration: 700
targets: notifyIcons,
width: 39,
opacity: 1,
easing: 'easeInQuint',
duration: 300
});
anime({
targets: notifyText,
backgroundColor: color,
easing: 'easeInOutQuint',
duration: 700,
opacity: 1,
easing: 'easeInOutQuad',
duration: 400,
complete: () => {
setTimeout(() => {
if (status !== null) {
anime({
targets: notify,
rotateX: '-120',
easing: 'easeInOutQuint',
duration: 700,
complete: () => {
targets: notifyText,
backgroundColor: color,
opacity: 0,
easing: 'easeInOutQuad',
duration: 400
});
anime({
targets: notifcation,
marginTop: '-55',
easing: 'easeInOutQuint',
delay: 700,
duration: 50
});
//notifcation.style.display = 'none';
}
});
}
}, 1000);
}
targets: notifyIcons,
width: 0,
opacity: 0,
easing: 'easeOutQuint',
duration: 350
});
}, 2000);
}
});
}

View file

@ -1,8 +1,8 @@
import * as DataEvent from "../events/DataEvent";
import { position } from "caret-pos";
import EventEmitter from "../events/EventEmitter";
import * as EditorEvent from "../events/EditorEvent";
import Prism from "prismjs";
import * as DataEvent from '../events/DataEvent';
import { position } from 'caret-pos';
import EventEmitter from '../events/EventEmitter';
import * as EditorEvent from '../events/EditorEvent';
import Prism from 'prismjs';
class TextEditor extends EventEmitter {
/**
* Text Editor UI Component
@ -16,40 +16,40 @@ class TextEditor extends EventEmitter {
constructor(textEditor, scrollLimit) {
super();
document.getElementById("edit").addEventListener("input", (e) => {
let result_element = document.querySelector("#highlight-content");
document.getElementById('edit').addEventListener('input', e => {
let result_element = document.querySelector('#highlight-content');
this.textEditor = textEditor;
// Update code
let text = e.target.value;
result_element.innerHTML = text
.replace(new RegExp("&", "g"), "&amp;")
.replace(new RegExp("<", "g"), "&lt;");
let editorHeight = document.getElementById("highlight").offsetHeight;
document.getElementById("edit-post-wrapper").style.height =
editorHeight + "px";
e.target.style.height = editorHeight + 30 + "px"; //TODO: yeah, it's ugly but it works for now, fix soon
.replace(new RegExp('&', 'g'), '&amp;')
.replace(new RegExp('<', 'g'), '&lt;');
let editorHeight = document.getElementById('highlight').offsetHeight;
document.querySelector('[role="edit-post-wrapper"]').style.height =
editorHeight + 'px';
e.target.style.height = editorHeight + 30 + 'px'; //TODO: yeah, it's ugly but it works for now, fix soon
// Syntax Highlight
Prism.highlightElement(result_element);
});
document.getElementById("edit").addEventListener("scroll", (e) => {
document.getElementById('edit').addEventListener('scroll', e => {
/* Scroll result to scroll coords of event - sync with textarea */
let result_element = document.querySelector("#highlight");
let result_element = document.querySelector('#highlight');
// Get and set x and y
result_element.scrollTop = e.scrollTop;
result_element.scrollLeft = e.scrollLeft;
});
document.getElementById("edit").dispatchEvent(new Event("input"));
document.getElementById('edit').dispatchEvent(new Event('input'));
this.setInputs();
//freeze editor formatting so it doesn't scroll off screen
window.addEventListener("scroll", () => {
window.addEventListener('scroll', () => {
var fixLimit = scrollLimit;
if (window.pageYOffset + 5 >= fixLimit) {
document.getElementById("edit-control").style.position = "fixed";
document.getElementById('edit-control').style.position = 'fixed';
} else {
document.getElementById("edit-control").style.position = "relative";
document.getElementById('edit-control').style.position = 'relative';
}
});
}
@ -57,11 +57,11 @@ class TextEditor extends EventEmitter {
// methods
//--------------------------
setInputs() {
var editorButtons = document.querySelectorAll(".editor-button");
var editorButtons = document.querySelectorAll('.editor-button');
for (var i = 0, length = editorButtons.length; i < length; i++) {
editorButtons[i].addEventListener(
"click",
(e) => this.handleEditorOption(e),
'click',
e => this.handleEditorOption(e),
false
);
}
@ -69,19 +69,19 @@ class TextEditor extends EventEmitter {
notify(type, data) {
switch (type) {
case DataEvent.PAGE_UPDATED:
document.getElementById("submit-update").classList.add("icon-hide");
document.getElementById("submit-good").classList.remove("icon-hide");
document.getElementById("edit-update").classList.remove("submit-start");
document.getElementById("edit-update").classList.add("submit-cool");
document.getElementById('submit-update').classList.add('icon-hide');
document.getElementById('submit-good').classList.remove('icon-hide');
document.getElementById('edit-update').classList.remove('submit-start');
document.getElementById('edit-update').classList.add('submit-cool');
setTimeout(() => {
document
.getElementById("submit-update")
.classList.remove("icon-hide");
document.getElementById("submit-good").classList.add("icon-hide");
document.getElementById("edit-update").classList.add("submit-start");
.getElementById('submit-update')
.classList.remove('icon-hide');
document.getElementById('submit-good').classList.add('icon-hide');
document.getElementById('edit-update').classList.add('submit-start');
document
.getElementById("edit-update")
.classList.remove("submit-cool");
.getElementById('edit-update')
.classList.remove('submit-cool');
}, 2000);
break;
case DataEvent.PAGE_ADDED:
@ -91,13 +91,13 @@ class TextEditor extends EventEmitter {
let len = this.textEditor.value.length;
let start = this.textEditor.selectionStart;
let end = this.textEditor.selectionEnd;
let insert = "![image alt text](" + data + ")";
let insert = '![image alt text](' + data + ')';
this.textEditor.value =
this.textEditor.value.substring(0, start) +
insert +
this.textEditor.value.substring(end, len);
document.getElementById("edit").dispatchEvent(new Event("input"));
document.getElementById('edit').dispatchEvent(new Event('input'));
break;
}
}
@ -112,83 +112,83 @@ class TextEditor extends EventEmitter {
let end = this.textEditor.selectionEnd;
let selectedText = this.textEditor.value.substring(start, end);
let insert = "";
let insert = '';
switch (e.target.id) {
case "edit-bold":
insert = "**" + selectedText + "**";
case 'edit-bold':
insert = '**' + selectedText + '**';
this.textEditor.value =
this.textEditor.value.substring(0, start) +
insert +
this.textEditor.value.substring(end, len);
break;
case "edit-italic":
insert = "*" + selectedText + "*";
case 'edit-italic':
insert = '*' + selectedText + '*';
//console.log(this.textEditor);
this.textEditor.value =
this.textEditor.value.substring(0, start) +
insert +
this.textEditor.value.substring(end, len);
break;
case "edit-strikethrough":
insert = "~~" + selectedText + "~~";
case 'edit-strikethrough':
insert = '~~' + selectedText + '~~';
this.textEditor.value =
this.textEditor.value.substring(0, start) +
insert +
this.textEditor.value.substring(end, len);
break;
case "edit-header1":
insert = "# " + selectedText + "\n";
case 'edit-header1':
insert = '# ' + selectedText + '\n';
this.textEditor.value =
this.textEditor.value.substring(0, start) +
insert +
this.textEditor.value.substring(end, len);
break;
case "edit-header2":
insert = "## " + selectedText + "\n";
case 'edit-header2':
insert = '## ' + selectedText + '\n';
this.textEditor.value =
this.textEditor.value.substring(0, start) +
insert +
this.textEditor.value.substring(end, len);
break;
case "edit-header3":
insert = "### " + selectedText + "\n";
case 'edit-header3':
insert = '### ' + selectedText + '\n';
this.textEditor.value =
this.textEditor.value.substring(0, start) +
insert +
this.textEditor.value.substring(end, len);
break;
case "edit-link":
case 'edit-link':
{
let url = prompt("Let's get that url, boss");
let link = url.toLowerCase();
insert = "[" + selectedText + "](" + link + ")";
insert = '[' + selectedText + '](' + link + ')';
this.textEditor.value =
this.textEditor.value.substring(0, start) +
insert +
this.textEditor.value.substring(end, len);
}
break;
case "edit-image":
case 'edit-image':
this.caretPos = position(this.textEditor).pos;
this.emitEvent(EditorEvent.EDITOR_UPLOAD_POST_IMAGE);
break;
case "submit-save":
case "edit-save":
case 'submit-save':
case 'edit-save':
this.emitEvent(EditorEvent.EDITOR_SAVE);
break;
case "submit-update":
case "edit-update":
case 'submit-update':
case 'edit-update':
this.emitEvent(EditorEvent.EDITOR_UPDATE);
break;
case "edit-delete":
case 'edit-delete':
this.emitEvent(EditorEvent.EDITOR_DELETE);
break;
default:
//do stuff
break;
}
document.getElementById("edit").dispatchEvent(new Event("input"));
document.getElementById('edit').dispatchEvent(new Event('input'));
}
}
export default TextEditor;

View file

@ -26,6 +26,8 @@ export default class DataUtils {
reject(
new Error(
"Image didn't load successfully; error code: " +
request.status +
' ' +
request.statusText
)
);

View file

@ -1,40 +1,40 @@
//** REQUEST TYPES **//
export const REQUEST_TYPE_POST = "POST";
export const REQUEST_TYPE_GET = "GET";
export const REQUEST_TYPE_PUT = "PUT";
export const REQUEST_TYPE_DELETE = "DELETE";
export const REQUEST_TYPE_POST = 'POST';
export const REQUEST_TYPE_GET = 'GET';
export const REQUEST_TYPE_PUT = 'PUT';
export const REQUEST_TYPE_DELETE = 'DELETE';
//** POST CONTENT TYPES **//
export const CONTENT_TYPE_JSON = "json";
export const CONTENT_TYPE_FORM = "x-www-form-urlencoded";
export const CONTENT_TYPE_JSON = 'json';
export const CONTENT_TYPE_FORM = 'x-www-form-urlencoded';
//** API URLS **//
export const API_STATUS = "/api/v1/status";
export const API_GET_SETTINGS = "/api/v1/settings/site";
export const API_GET_MEMBER_INFO = "/api/v1/settings/member";
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_SETTINGS_SYNC = "/api/v1/settings/sync";
export const API_PUBLISH_PAGES = "/api/v1/settings/publish";
export const API_NAV_SYNC = "/api/v1/settings/nav-sync";
export const API_REINDEX_PAGES = "/api/v1/settings/reindex";
export const API_SEND_MAIL = "/api/v1/mailer";
export const API_LOGIN = "/api/v1/login";
export const API_STATUS = '/api/v1/status';
export const API_GET_SETTINGS = '/api/v1/settings/site';
export const API_GET_MEMBER_INFO = '/api/v1/settings/member';
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_SETTINGS_SYNC = '/api/v1/settings/sync';
export const API_PUBLISH_PAGES = '/api/v1/settings/publish';
export const API_NAV_SYNC = '/api/v1/settings/nav-sync';
export const API_REINDEX_PAGES = '/api/v1/settings/reindex';
export const API_SEND_MAIL = '/api/v1/mailer';
export const API_LOGIN = '/api/v1/login';
//** API TASKS **//
export const AUTH_STATUS = "getAuthStatus";
export const TASK_SETTINGS_WRITE = "writeSettings";
export const TASK_PUBLISH_SITE = "publishSite";
export const TASK_PAGE_CREATE = "createNewPage";
export const TASK_PAGE_EDIT = "editPage";
export const TASK_PAGE_DELETE = "deletePage";
export const TASK_SEND_MAIL = "sendMail";
export const TASK_REINDEX_PAGE = "reIndexPages";
export const TASK_SYNC_SETTNIGS = "syncSite";
export const TASK_SYNC_NAV = "syncNav";
export const TASK_GET_SETTINGS = "getSiteSettings";
export const TASK_GET_MEMBER_INFO = "getMemberInfo";
export const AUTH_STATUS = 'getAuthStatus';
export const TASK_SETTINGS_WRITE = 'writeSettings';
export const TASK_PUBLISH_SITE = 'publishSite';
export const TASK_PAGE_CREATE = 'createNewPage';
export const TASK_PAGE_EDIT = 'editPage';
export const TASK_PAGE_DELETE = 'deletePage';
export const TASK_SEND_MAIL = 'sendMail';
export const TASK_REINDEX_PAGE = 'reIndexPages';
export const TASK_SYNC_SETTNIGS = 'syncSite';
export const TASK_SYNC_NAV = 'syncNav';
export const TASK_GET_SETTINGS = 'getSiteSettings';
export const TASK_GET_MEMBER_INFO = 'getMemberInfo';
//** API STATUS **//
export const API_ACCESS_GOOD = "apiUseAuthorized";
export const API_ACCESS_BAD = "apiUseNotAuthorized";
export const API_ACCESS_GOOD = 'apiUseAuthorized';
export const API_ACCESS_BAD = 'apiUseNotAuthorized';
/**
* A can of methods used to edit install settings, navigation pages and content pages
@ -54,7 +54,7 @@ class FipamoAdminAPI {
if (baseURL) this.baseURL = baseURL;
//asks server if a session is active
this._request(this.baseURL ? this.baseURL + API_STATUS : API_STATUS).then(
(response) => {
response => {
if (response.type === API_ACCESS_GOOD) {
this.token = response.token;
} else {
@ -93,10 +93,10 @@ class FipamoAdminAPI {
CONTENT_TYPE_JSON,
data
)
.then((result) => {
.then(result => {
resolve(result);
})
.catch((err) => {
.catch(err => {
reject(err);
});
});
@ -142,12 +142,12 @@ class FipamoAdminAPI {
*/
sync(task, data) {
return new Promise((resolve, reject) => {
let url = "";
let url = '';
switch (task) {
case "syncSite":
case 'syncSite':
url = API_SETTINGS_SYNC;
break;
case "syncNav":
case 'syncNav':
url = API_NAV_SYNC;
break;
}
@ -158,10 +158,10 @@ class FipamoAdminAPI {
CONTENT_TYPE_JSON,
data
)
.then((result) => {
.then(result => {
resolve(result);
})
.catch((err) => {
.catch(err => {
reject(err);
});
});
@ -193,10 +193,10 @@ class FipamoAdminAPI {
CONTENT_TYPE_JSON,
data
)
.then((result) => {
.then(result => {
resolve(result);
})
.catch((err) => {
.catch(err => {
reject(err);
});
});
@ -239,18 +239,18 @@ class FipamoAdminAPI {
case TASK_PAGE_CREATE:
url = API_NEW_PAGE;
event = TASK_PAGE_CREATE;
content = CONTENT_TYPE_FORM;
content = CONTENT_TYPE_JSON;
break;
case TASK_PAGE_EDIT:
url = API_EDIT_PAGE;
event = TASK_PAGE_EDIT;
content = CONTENT_TYPE_FORM;
content = CONTENT_TYPE_JSON;
break;
case TASK_PAGE_DELETE:
url = API_DELETE_PAGE;
event = TASK_PAGE_DELETE;
content = CONTENT_TYPE_FORM;
content = CONTENT_TYPE_JSON;
break;
default:
@ -272,10 +272,10 @@ class FipamoAdminAPI {
content,
data
)
.then((result) => {
.then(result => {
resolve(result);
})
.catch((err) => {
.catch(err => {
reject(err);
});
});
@ -307,10 +307,10 @@ class FipamoAdminAPI {
CONTENT_TYPE_JSON,
message
)
.then((result) => {
.then(result => {
resolve(result);
})
.catch((err) => {
.catch(err => {
reject(err);
});
});
@ -338,7 +338,7 @@ class FipamoAdminAPI {
getInfo(type) {
let url, task;
if (type == "site") {
if (type == 'site') {
url = API_GET_SETTINGS;
task = TASK_GET_SETTINGS;
} else {
@ -347,10 +347,10 @@ class FipamoAdminAPI {
}
return new Promise((resolve, reject) => {
this._request(this.baseURL ? this.baseURL + url : url, task)
.then((result) => {
.then(result => {
resolve(result);
})
.catch((err) => {
.catch(err => {
reject(err);
});
});
@ -369,16 +369,16 @@ class FipamoAdminAPI {
var self = this;
return new Promise(function (resolve, reject) {
var request = new XMLHttpRequest();
request.upload.addEventListener("progress", (e) =>
request.upload.addEventListener('progress', e =>
self.handleLoadProgress(e, self.progressBar)
);
request.open(requestType, requestURL, true);
request.onload = () => {
if (request.status == 200) {
let response = JSON.parse(request["response"]);
let response = JSON.parse(request['response']);
resolve(response);
} else {
let error = JSON.parse(request["response"]);
let error = JSON.parse(request['response']);
reject(error);
}
};
@ -391,13 +391,13 @@ class FipamoAdminAPI {
eventType === TASK_PUBLISH_SITE ||
eventType === TASK_REINDEX_PAGE
)
request.setRequestHeader("fipamo-access-token", self.token);
request.setRequestHeader('fipamo-access-token', self.token);
switch (contentType) {
case CONTENT_TYPE_JSON:
request.setRequestHeader(
"Content-type",
"application/" + contentType
'Content-type',
'application/' + contentType
);
request.send(JSON.stringify(requestData));
break;
@ -410,7 +410,7 @@ class FipamoAdminAPI {
eventType === TASK_GET_SETTINGS ||
eventType === TASK_GET_MEMBER_INFO
) {
request.setRequestHeader("fipamo-access-token", self.token);
request.setRequestHeader('fipamo-access-token', self.token);
}
request.send();
}
@ -424,7 +424,7 @@ class FipamoAdminAPI {
let percent = Math.ceil((e.loaded / e.total) * 100);
//if a progress bar element is present, talk to it
if (progressBar != null) {
progressBar.style.width = percent + "%";
progressBar.style.width = percent + '%';
}
}
}