Merge branch '395-custom-blocks-to-database' into '3-1-0'
Move Custom Blocks/Nav Elements to Database See merge request !60inline-attachment-viewing
commit
09c650d487
@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
define('IN_SCRIPT', 1);
|
||||
define('HESK_PATH', '../');
|
||||
define('PAGE_TITLE', 'ADMIN_CUSTOM_NAV_ELEMENTS');
|
||||
define('MFH_PAGE_LAYOUT', 'TOP_ONLY');
|
||||
define('EXTRA_JS', '<script src="'.HESK_PATH.'internal-api/js/manage-custom-nav-elements.js"></script>');
|
||||
|
||||
/* Get all the required files and functions */
|
||||
require(HESK_PATH . 'hesk_settings.inc.php');
|
||||
require(HESK_PATH . 'inc/common.inc.php');
|
||||
require(HESK_PATH . 'inc/admin_functions.inc.php');
|
||||
require(HESK_PATH . 'inc/mail_functions.inc.php');
|
||||
hesk_load_database_functions();
|
||||
|
||||
hesk_session_start();
|
||||
hesk_dbConnect();
|
||||
hesk_isLoggedIn();
|
||||
|
||||
//hesk_checkPermission('can_man_custom_nav');
|
||||
|
||||
/* Print header */
|
||||
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
|
||||
|
||||
/* Print main manage users page */
|
||||
require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
?>
|
||||
<div class="content-wrapper">
|
||||
<section class="content">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h1 class="box-title">
|
||||
<?php echo $hesklang['custom_nav_menu_elements']; ?>
|
||||
</h1>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse">
|
||||
<i class="fa fa-minus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-right">
|
||||
<button id="create-button" class="btn btn-success">
|
||||
<i class="fa fa-plus-circle"></i>
|
||||
<?php echo $hesklang['create_new']; ?>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo $hesklang['id']; ?></th>
|
||||
<th><?php echo $hesklang['custom_nav_text']; ?></th>
|
||||
<th><?php echo $hesklang['custom_nav_subtext']; ?></th>
|
||||
<th><?php echo $hesklang['image_url_slash_font_icon']; ?></th>
|
||||
<th><?php echo $hesklang['url']; ?></th>
|
||||
<th><?php echo $hesklang['actions']; ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="table-body">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay" id="overlay">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="modal fade" id="nav-element-modal" tabindex="-1" role="dialog" style="overflow: hidden">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="cursor: move">
|
||||
<button type="button" class="close cancel-callback" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="edit-label">
|
||||
<?php echo $hesklang['edit_custom_nav_element_title_case']; ?>
|
||||
</h4>
|
||||
<h4 class="modal-title" id="create-label">
|
||||
<?php echo $hesklang['create_custom_nav_element_title_case']; ?>
|
||||
</h4>
|
||||
</div>
|
||||
<form id="manage-nav-element" class="form-horizontal" data-toggle="validator">
|
||||
<input type="hidden" name="id">
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="place" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $hesklang['place']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
|
||||
title="<?php echo $hesklang['place']; ?>"
|
||||
data-content="<?php echo $hesklang['place_help']; ?>"></i>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<select name="place" id="place" class="form-control"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<option value="1"><?php echo $hesklang['homepage_block']; ?></option>
|
||||
<option value="2"><?php echo $hesklang['customer_navigation']; ?></option>
|
||||
<option value="3"><?php echo $hesklang['staff_navigation']; ?></option>
|
||||
</select>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<h4><?php echo $hesklang['custom_nav_text']; ?></h4>
|
||||
<?php foreach ($hesk_settings['languages'] as $language => $value): ?>
|
||||
<div class="form-group">
|
||||
<label for="text[<?php echo $language; ?>]" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $language; ?>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<input type="text" name="text" class="form-control"
|
||||
data-text-language="<?php echo $language; ?>"
|
||||
id="text[<?php echo $language; ?>" placeholder="<?php echo $hesklang['custom_nav_text']; ?>"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<div id="subtext">
|
||||
<h4><?php echo $hesklang['custom_nav_subtext']; ?></h4>
|
||||
<?php foreach ($hesk_settings['languages'] as $language => $value): ?>
|
||||
<div class="form-group">
|
||||
<label for="subtext[<?php echo $language; ?>]" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $language; ?>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<input type="text" name="subtext" class="form-control"
|
||||
data-subtext-language="<?php echo $language; ?>"
|
||||
id="subtext[<?php echo $language; ?>" placeholder="<?php echo $hesklang['custom_nav_subtext']; ?>"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<h4><?php echo $hesklang['url']; ?></h4>
|
||||
<div class="form-group">
|
||||
<label for="image-type" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $hesklang['url']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
|
||||
title="<?php echo $hesklang['url']; ?>"
|
||||
data-content="<?php echo $hesklang['url_help']; ?>"></i>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<input type="text" name="url" class="form-control"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
placeholder="<?php echo $hesklang['url']; ?>" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<h4><?php echo $hesklang['image']; ?></h4>
|
||||
<div class="form-group">
|
||||
<label for="image-type" class="col-md-4 col-sm-12 control-label"><?php echo $hesklang['image_type']; ?></label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<select name="image-type" id="image-type" class="form-control"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<option value="image-url"><?php echo $hesklang['image_url']; ?></option>
|
||||
<option value="font-icon"><?php echo $hesklang['font_icon']; ?></option>
|
||||
</select>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="image-url-group">
|
||||
<label for="image-url" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $hesklang['image_url']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
|
||||
title="<?php echo $hesklang['image_url']; ?>"
|
||||
data-content="<?php echo $hesklang['image_url_help']; ?>"></i>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<input type="text" name="image-url" class="form-control"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
placeholder="<?php echo $hesklang['image_url']; ?>" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="font-icon-group">
|
||||
<p style="display:none" id="no-icon"><?php echo $hesklang['sm_no_icon']; ?></p>
|
||||
|
||||
<p style="display:none" id="search-icon"><?php echo $hesklang['sm_search_icon']; ?></p>
|
||||
|
||||
<p style="display:none"
|
||||
id="footer-icon"><?php echo $hesklang['sm_iconpicker_footer_label']; ?></p>
|
||||
<label for="font-icon" class="col-md-4 col-sm-12 control-label"><?php echo $hesklang['font_icon']; ?></label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<div class="btn btn-default iconpicker-container" data-toggle="nav-iconpicker">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="btn-group" id="action-buttons">
|
||||
<button type="button" class="btn btn-default cancel-button" data-dismiss="modal">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<span><?php echo $hesklang['cancel']; ?></span>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-success save-button">
|
||||
<i class="fa fa-check-circle"></i>
|
||||
<span><?php echo $hesklang['save']; ?></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
echo mfh_get_hidden_fields_for_language(
|
||||
array(
|
||||
'edit',
|
||||
'delete',
|
||||
'no_custom_nav_elements_found',
|
||||
'failed_to_load_custom_nav_elements',
|
||||
'custom_nav_element_deleted',
|
||||
'error_deleting_custom_nav_element',
|
||||
'error_sorting_custom_nav_elements',
|
||||
'custom_nav_element_created',
|
||||
'custom_nav_element_saved',
|
||||
'homepage_block',
|
||||
'customer_navigation',
|
||||
'staff_navigation',
|
||||
'error_saving_custom_nav_element',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<script type="text/html" id="nav-element-template">
|
||||
<tr>
|
||||
<td><span data-property="id" data-value="x"></span></td>
|
||||
<td><span>
|
||||
<ul data-property="text" class="list-unstyled"></ul>
|
||||
</span></td>
|
||||
<td><span>
|
||||
<ul data-property="subtext" class="list-unstyled"></ul>
|
||||
</span></td>
|
||||
<td><span data-property="image-or-font"></span></td>
|
||||
<td><span data-property="url"></span></td>
|
||||
<td>
|
||||
<a href="#" data-action="sort"
|
||||
data-direction="up">
|
||||
<i class="fa fa-fw fa-arrow-up icon-link green"
|
||||
data-toggle="tooltip" title="<?php echo $hesklang['move_up']; ?>"></i>
|
||||
</a>
|
||||
<a href="#" data-action="sort"
|
||||
data-direction="down">
|
||||
<i class="fa fa-fw fa-arrow-down icon-link green"
|
||||
data-toggle="tooltip" title="<?php echo $hesklang['move_dn'] ?>"></i>
|
||||
</a>
|
||||
<a href="#" data-action="edit">
|
||||
<i class="fa fa-fw fa-pencil icon-link orange"
|
||||
data-toggle="tooltip" title="<?php echo $hesklang['edit']; ?>"></i>
|
||||
</a>
|
||||
<a href="#" data-action="delete">
|
||||
<i class="fa fa-fw fa-times icon-link red"
|
||||
data-toggle="tooltip" title="<?php echo $hesklang['delete']; ?>"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
<?php
|
||||
require_once(HESK_PATH . 'inc/footer.inc.php');
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
|
||||
class CustomNavElement {
|
||||
/* @var $id int*/
|
||||
public $id;
|
||||
|
||||
/* @var $text string[] */
|
||||
public $text;
|
||||
|
||||
/* @var $subtext string[]|null */
|
||||
public $subtext;
|
||||
|
||||
/* @var $imageUrl string|null */
|
||||
public $imageUrl;
|
||||
|
||||
/* @var $fontIcon string|null */
|
||||
public $fontIcon;
|
||||
|
||||
/* @var $place int */
|
||||
public $place;
|
||||
|
||||
/* @var $url string */
|
||||
public $url;
|
||||
|
||||
/* @var $sort int */
|
||||
public $sort;
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
// TODO Test!
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use DataAccess\Navigation\CustomNavElementGateway;
|
||||
|
||||
class CustomNavElementHandler {
|
||||
/* @var $customNavElementGateway CustomNavElementGateway */
|
||||
private $customNavElementGateway;
|
||||
|
||||
function __construct($customNavElementGateway) {
|
||||
$this->customNavElementGateway = $customNavElementGateway;
|
||||
}
|
||||
|
||||
|
||||
function getAllCustomNavElements($heskSettings) {
|
||||
return $this->customNavElementGateway->getAllCustomNavElements($heskSettings);
|
||||
}
|
||||
|
||||
function getCustomNavElement($id, $heskSettings) {
|
||||
$elements = $this->getAllCustomNavElements($heskSettings);
|
||||
|
||||
foreach ($elements as $element) {
|
||||
if ($element->id === intval($id)) {
|
||||
return output($element);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ApiFriendlyException("Custom nav element {$id} not found!", "Element Not Found", 404);
|
||||
}
|
||||
|
||||
function deleteCustomNavElement($id, $heskSettings) {
|
||||
$this->customNavElementGateway->deleteCustomNavElement($id, $heskSettings);
|
||||
$this->customNavElementGateway->resortAllElements($heskSettings);
|
||||
}
|
||||
|
||||
function saveCustomNavElement($element, $heskSettings) {
|
||||
$this->customNavElementGateway->saveCustomNavElement($element, $heskSettings);
|
||||
}
|
||||
|
||||
function createCustomNavElement($element, $heskSettings) {
|
||||
$element = $this->customNavElementGateway->createCustomNavElement($element, $heskSettings);
|
||||
$this->customNavElementGateway->resortAllElements($heskSettings);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
function sortCustomNavElement($elementId, $direction, $heskSettings) {
|
||||
/* @var $element CustomNavElement */
|
||||
$elements = $this->customNavElementGateway->getAllCustomNavElements($heskSettings);
|
||||
$elementToChange = null;
|
||||
foreach ($elements as $element) {
|
||||
if ($element->id === intval($elementId)) {
|
||||
$elementToChange = $element;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($direction === Direction::UP) {
|
||||
$elementToChange->sort -= 15;
|
||||
} else {
|
||||
$elementToChange->sort += 15;
|
||||
}
|
||||
|
||||
$this->customNavElementGateway->saveCustomNavElement($elementToChange, $heskSettings);
|
||||
$this->customNavElementGateway->resortAllElements($heskSettings);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
|
||||
class CustomNavElementPlace {
|
||||
const HOMEPAGE_BLOCK = 1;
|
||||
const CUSTOMER_NAVIGATION = 2;
|
||||
const ADMIN_NAVIGATION = 3;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
|
||||
class Direction {
|
||||
const UP = 'up';
|
||||
const DOWN = 'down';
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Navigation;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Helpers;
|
||||
use BusinessLogic\Navigation\CustomNavElement;
|
||||
use BusinessLogic\Navigation\CustomNavElementHandler;
|
||||
use Controllers\InternalApiController;
|
||||
use Controllers\JsonRetriever;
|
||||
|
||||
class CustomNavElementController extends InternalApiController {
|
||||
static function getAll() {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
self::staticCheckForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
output($handler->getAllCustomNavElements($hesk_settings));
|
||||
}
|
||||
|
||||
static function sort($id, $direction) {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
self::staticCheckForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
$handler->sortCustomNavElement(intval($id), $direction, $hesk_settings);
|
||||
}
|
||||
|
||||
function get($id) {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$this->checkForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
output($handler->getCustomNavElement($id, $hesk_settings));
|
||||
}
|
||||
|
||||
function post() {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$this->checkForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
$data = JsonRetriever::getJsonData();
|
||||
$element = $handler->createCustomNavElement($this->buildElementModel($data), $hesk_settings);
|
||||
|
||||
return output($element, 201);
|
||||
}
|
||||
|
||||
function put($id) {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$this->checkForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
$data = JsonRetriever::getJsonData();
|
||||
$handler->saveCustomNavElement($this->buildElementModel($data, $id), $hesk_settings);
|
||||
|
||||
return http_response_code(204);
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$this->checkForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
$handler->deleteCustomNavElement($id, $hesk_settings);
|
||||
|
||||
return http_response_code(204);
|
||||
}
|
||||
|
||||
private function buildElementModel($data, $id = null) {
|
||||
$element = new CustomNavElement();
|
||||
$element->id = $id;
|
||||
$element->place = intval(Helpers::safeArrayGet($data, 'place'));
|
||||
$element->fontIcon = Helpers::safeArrayGet($data, 'fontIcon');
|
||||
$element->imageUrl = Helpers::safeArrayGet($data, 'imageUrl');
|
||||
$element->text = Helpers::safeArrayGet($data, 'text');
|
||||
$element->subtext = Helpers::safeArrayGet($data, 'subtext');
|
||||
$element->url = Helpers::safeArrayGet($data, 'url');
|
||||
$element->sort = intval(Helpers::safeArrayGet($data, 'sort'));
|
||||
|
||||
return $element;
|
||||
}
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
<?php
|
||||
|
||||
function print_error($title, $message, $response_code = 500) {
|
||||
function print_error($title, $message, $logId = null, $response_code = 500) {
|
||||
require_once(__DIR__ . '/output.php');
|
||||
|
||||
$error = array();
|
||||
$error['type'] = 'ERROR';
|
||||
$error['title'] = $title;
|
||||
$error['message'] = $message;
|
||||
$error['logId'] = $logId;
|
||||
|
||||
print output($error, $response_code);
|
||||
return;
|
||||
|
@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace DataAccess\Navigation;
|
||||
|
||||
|
||||
use BusinessLogic\Navigation\CustomNavElement;
|
||||
use DataAccess\CommonDao;
|
||||
|
||||
class CustomNavElementGateway extends CommonDao {
|
||||
function getAllCustomNavElements($heskSettings) {
|
||||
$this->init();
|
||||
|
||||
$columns = '`t1`.`id`, `t1`.`image_url`, `t1`.`font_icon`, `t1`.`place`, `t1`.`url`, `t1`.`sort`,
|
||||
`t2`.`language`, `t2`.`text`, `t2`.`subtext`';
|
||||
|
||||
$rs = hesk_dbQuery("SELECT {$columns} FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element` AS `t1`
|
||||
INNER JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element_to_text` AS `t2`
|
||||
ON `t1`.`id` = `t2`.`nav_element_id`
|
||||
ORDER BY `t1`.`place` ASC, `t1`.`sort` ASC");
|
||||
|
||||
$elements = array();
|
||||
|
||||
/* @var $element CustomNavElement */
|
||||
$element = null;
|
||||
$previousId = -1;
|
||||
while ($row = hesk_dbFetchAssoc($rs)) {
|
||||
$id = intval($row['id']);
|
||||
if ($previousId !== $id) {
|
||||
if ($element !== null) {
|
||||
$elements[] = $element;
|
||||
}
|
||||
$element = new CustomNavElement();
|
||||
$element->id = $id;
|
||||
$element->place = intval($row['place']);
|
||||
$element->imageUrl = $row['image_url'];
|
||||
$element->fontIcon = $row['font_icon'];
|
||||
$element->url = $row['url'];
|
||||
$element->sort = $row['sort'];
|
||||
$element->text = array();
|
||||
$element->subtext = array();
|
||||
}
|
||||
|
||||
$element->text[$row['language']] = $row['text'];
|
||||
$element->subtext[$row['language']] = $row['subtext'];
|
||||
|
||||
$previousId = $id;
|
||||
}
|
||||
|
||||
if ($element !== null) {
|
||||
$elements[] = $element;
|
||||
}
|
||||
|
||||
$this->close();
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id int
|
||||
* @param $heskSettings array
|
||||
*/
|
||||
function deleteCustomNavElement($id, $heskSettings) {
|
||||
$this->init();
|
||||
|
||||
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element_to_text`
|
||||
WHERE `nav_element_id` = " . intval($id));
|
||||
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element`
|
||||
WHERE `id` = " . intval($id));
|
||||
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $element CustomNavElement
|
||||
* @param $heskSettings array
|
||||
*/
|
||||
function saveCustomNavElement($element, $heskSettings) {
|
||||
$this->init();
|
||||
|
||||
//-- Delete previous records - easier than inserting/updating
|
||||
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element_to_text`
|
||||
WHERE `nav_element_id` = " . intval($element->id));
|
||||
|
||||
$languageTextAndSubtext = array();
|
||||
foreach ($element->text as $key => $text) {
|
||||
$languageTextAndSubtext[$key]['text'] = $text;
|
||||
}
|
||||
foreach ($element->subtext as $key => $subtext) {
|
||||
$languageTextAndSubtext[$key]['subtext'] = $subtext;
|
||||
}
|
||||
|
||||
foreach ($languageTextAndSubtext as $key => $values) {
|
||||
$subtext = 'NULL';
|
||||
if (isset($values['subtext'])) {
|
||||
$subtext = "'" . hesk_dbEscape($values['subtext']) . "'";
|
||||
}
|
||||
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element_to_text`
|
||||
(`nav_element_id`, `language`, `text`, `subtext`) VALUES (" . intval($element->id) . ",
|
||||
'" . hesk_dbEscape($key) . "',
|
||||
'" . hesk_dbEscape($values['text']) . "',
|
||||
" . $subtext . ")");
|
||||
}
|
||||
|
||||
$imageUrl = $element->imageUrl == null ? 'NULL' : "'" . hesk_dbEscape($element->imageUrl) . "'";
|
||||
$fontIcon = $element->fontIcon == null ? 'NULL' : "'" . hesk_dbEscape($element->fontIcon) . "'";
|
||||
hesk_dbQuery("UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element`
|
||||
SET `image_url` = {$imageUrl},
|
||||
`font_icon` = {$fontIcon},
|
||||
`url` = '" . hesk_dbEscape($element->url) . "',
|
||||
`sort` = " . intval($element->sort) . ",
|
||||
`place` = " . intval($element->place) .
|
||||
" WHERE `id` = " . intval($element->id));
|
||||
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $element CustomNavElement
|
||||
* @param $heskSettings array
|
||||
* @return CustomNavElement
|
||||
*/
|
||||
function createCustomNavElement($element, $heskSettings) {
|
||||
$this->init();
|
||||
|
||||
$rs = hesk_dbQuery("SELECT MAX(`sort`) AS `sort` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element`
|
||||
WHERE `place` = " . intval($element->place));
|
||||
$maxSort = hesk_dbFetchAssoc($rs);
|
||||
$sortValue = intval($maxSort['sort']) + 1;
|
||||
|
||||
$imageUrl = $element->imageUrl == null ? 'NULL' : "'" . hesk_dbEscape($element->imageUrl) . "'";
|
||||
$fontIcon = $element->fontIcon == null ? 'NULL' : "'" . hesk_dbEscape($element->fontIcon) . "'";
|
||||
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element`
|
||||
(`image_url`, `font_icon`, `place`, `sort`, `url`)
|
||||
VALUES ({$imageUrl}, {$fontIcon}, " . intval($element->place) . ", " . $sortValue . ", '" . hesk_dbEscape($element->url) . "')");
|
||||
|
||||
$element->id = hesk_dbInsertID();
|
||||
|
||||
|
||||
$languageTextAndSubtext = array();
|
||||
foreach ($element->text as $key => $text) {
|
||||
$languageTextAndSubtext[$key]['text'] = $text;
|
||||
}
|
||||
foreach ($element->subtext as $key => $subtext) {
|
||||
$languageTextAndSubtext[$key]['subtext'] = $subtext;
|
||||
}
|
||||
|
||||
foreach ($languageTextAndSubtext as $key => $values) {
|
||||
$subtext = 'NULL';
|
||||
if (isset($values['subtext'])) {
|
||||
$subtext = "'" . hesk_dbEscape($values['subtext']) . "'";
|
||||
}
|
||||
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element_to_text`
|
||||
(`nav_element_id`, `language`, `text`, `subtext`) VALUES (" . intval($element->id) . ",
|
||||
'" . hesk_dbEscape($key) . "',
|
||||
'" . hesk_dbEscape($values['text']) . "',
|
||||
" . $subtext . ")");
|
||||
}
|
||||
|
||||
$this->close();
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
|
||||
function resortAllElements($heskSettings) {
|
||||
$this->init();
|
||||
|
||||
$rs = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element`
|
||||
ORDER BY `place` ASC, `sort` ASC");
|
||||
|
||||
$sortValue = 10;
|
||||
while ($row = hesk_dbFetchAssoc($rs)) {
|
||||
hesk_dbQuery("UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element`
|
||||
SET `sort` = " . intval($sortValue) . "
|
||||
WHERE `id` = " . intval($row['id']));
|
||||
|
||||
$sortValue += 10;
|
||||
}
|
||||
|
||||
$this->close();
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,31 @@
|
||||
var mfhAlert = {
|
||||
success: success,
|
||||
error: error,
|
||||
errorWithLog: errorWithLog
|
||||
};
|
||||
|
||||
function success(message, title) {
|
||||
if (title === undefined) {
|
||||
title = $('#lang_alert_success').text();
|
||||
}
|
||||
|
||||
toastr.success(message, title);
|
||||
}
|
||||
|
||||
function error(message, title) {
|
||||
if (title === undefined) {
|
||||
title = $('#lang_alert_error').text();
|
||||
}
|
||||
|
||||
toastr.error(message, title);
|
||||
}
|
||||
|
||||
function errorWithLog(message, responseJSON, title) {
|
||||
var displayMessage = message;
|
||||
if (responseJSON !== undefined &&
|
||||
responseJSON.logId !== undefined) {
|
||||
displayMessage += ' (' + responseJSON.logId + ')';
|
||||
}
|
||||
|
||||
mfhAlert.error(displayMessage, title);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
var mfhLang = {
|
||||
text: function(key) {
|
||||
return $('#lang_' + key).text();
|
||||
}
|
||||
};
|
@ -0,0 +1,350 @@
|
||||
var elements = [];
|
||||
|
||||
$(document).ready(function() {
|
||||
loadTable();
|
||||
bindEditModal();
|
||||
bindCreateModal();
|
||||
bindDeleteButton();
|
||||
bindSortButtons();
|
||||
|
||||
$('[data-toggle="nav-iconpicker"]').iconpicker({
|
||||
iconset: ['fontawesome', 'octicon'],
|
||||
selectedClass: "btn-warning",
|
||||
labelNoIcon: $('#no-icon').text(),
|
||||
searchText: $('#search-icon').text(),
|
||||
labelFooter: $('#footer-icon').text(),
|
||||
resetButton: false,
|
||||
search: false,
|
||||
icon: 'fa fa-adn'
|
||||
});
|
||||
|
||||
$('select[name="place"]').change(function() {
|
||||
var $subtextField = $('#subtext');
|
||||
if (parseInt($(this).val()) === 1) {
|
||||
$subtextField.show();
|
||||
} else {
|
||||
$subtextField.hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('select[name="image-type"]').change(function() {
|
||||
var $imageUrl = $('#image-url-group');
|
||||
var $fontIcon = $('#font-icon-group');
|
||||
|
||||
if ($(this).val() === 'image-url') {
|
||||
$imageUrl.show();
|
||||
$fontIcon.hide();
|
||||
} else {
|
||||
$imageUrl.hide();
|
||||
$fontIcon.show();
|
||||
}
|
||||
});
|
||||
|
||||
$('form#manage-nav-element').submit(function(e) {
|
||||
e.preventDefault();
|
||||
var heskUrl = $('#heskUrl').text();
|
||||
|
||||
var $modal = $('#nav-element-modal');
|
||||
|
||||
var place = parseInt($modal.find('select[name="place"]').val());
|
||||
|
||||
var $textLanguages = $modal.find('[data-text-language]');
|
||||
var text = {};
|
||||
$.each($textLanguages, function() {
|
||||
text[$(this).data('text-language')] = $(this).val();
|
||||
});
|
||||
|
||||
var subtext = {};
|
||||
if (place === 1) {
|
||||
var $subtextLanguages = $modal.find('[data-subtext-language]');
|
||||
$.each($subtextLanguages, function() {
|
||||
subtext[$(this).data('subtext-language')] = $(this).val();
|
||||
});
|
||||
}
|
||||
|
||||
var imageUrl = null;
|
||||
var fontIcon = null;
|
||||
if ($modal.find('select[name="image-type"]').val() === 'image-url') {
|
||||
imageUrl = $modal.find('input[name="image-url"]').val();
|
||||
} else {
|
||||
fontIcon = $modal.find('.iconpicker').find('input[type="hidden"]').val();
|
||||
}
|
||||
|
||||
var id = parseInt($modal.find('input[name="id"]').val());
|
||||
var navUrl = $modal.find('input[name="url"]').val();
|
||||
|
||||
var data = {
|
||||
place: place,
|
||||
text: text,
|
||||
subtext: subtext,
|
||||
imageUrl: imageUrl,
|
||||
fontIcon: fontIcon,
|
||||
url: navUrl
|
||||
};
|
||||
|
||||
var url = heskUrl + '/api/v1-internal/custom-navigation/';
|
||||
var method = 'POST';
|
||||
|
||||
if (id !== -1) {
|
||||
url += id;
|
||||
method = 'PUT';
|
||||
}
|
||||
|
||||
$modal.find('#action-buttons').find('.cancel-button').attr('disabled', 'disabled');
|
||||
$modal.find('#action-buttons').find('.save-button').attr('disabled', 'disabled');
|
||||
|
||||
$.ajax({
|
||||
method: method,
|
||||
url: url,
|
||||
headers: { 'X-Internal-Call': true },
|
||||
data: JSON.stringify(data),
|
||||
success: function(data) {
|
||||
if (id === -1) {
|
||||
mfhAlert.success(mfhLang.text('custom_nav_element_created'));
|
||||
} else {
|
||||
mfhAlert.success(mfhLang.text('custom_nav_element_saved'));
|
||||
}
|
||||
$modal.modal('hide');
|
||||
loadTable();
|
||||
},
|
||||
error: function(data) {
|
||||
mfhAlert.errorWithLog(mfhLang.text('error_saving_custom_nav_element'), data.responseJSON);
|
||||
console.error(data);
|
||||
},
|
||||
complete: function() {
|
||||
$modal.find('#action-buttons').find('.cancel-button').removeAttr('disabled');
|
||||
$modal.find('#action-buttons').find('.save-button').removeAttr('disabled');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function loadTable() {
|
||||
$('#overlay').show();
|
||||
var heskUrl = $('#heskUrl').text();
|
||||
var notFoundText = mfhLang.text('no_custom_nav_elements_found');
|
||||
var places = [];
|
||||
var $tableBody = $('#table-body');
|
||||
places[1] = mfhLang.text('homepage_block');
|
||||
places[2] = mfhLang.text('customer_navigation');
|
||||
places[3] = mfhLang.text('staff_navigation');
|
||||
|
||||
$.ajax({
|
||||
method: 'GET',
|
||||
url: heskUrl + '/api/v1-internal/custom-navigation/all',
|
||||
headers: { 'X-Internal-Call': true },
|
||||
success: function(data) {
|
||||
$tableBody.html('');
|
||||
elements = [];
|
||||
|
||||
if (data.length === 0) {
|
||||
$('#table-body').append('<tr><td colspan="6">' + notFoundText + '</td></tr>');
|
||||
return;
|
||||
}
|
||||
|
||||
var currentPlace = 0;
|
||||
var addedElementToPlace = false;
|
||||
var first = true;
|
||||
var lastElement = null;
|
||||
$.each(data, function() {
|
||||
if (this.place !== currentPlace) {
|
||||
if (lastElement !== null) {
|
||||
//-- Hide the down arrow on the last element
|
||||
$('[data-value="' + lastElement.id + '"]').parent().parent()
|
||||
.find('[data-direction="down"]').css('visibility', 'hidden');
|
||||
lastElement = null;
|
||||
}
|
||||
|
||||
$('#table-body').append('<tr><td colspan="6" class="bg-gray"><i><b>' + places[this.place] + '</b></i></td></tr>');
|
||||
currentPlace = this.place;
|
||||
addedElementToPlace = false;
|
||||
first = true;
|
||||
}
|
||||
|
||||
var $template = $($('#nav-element-template').html());
|
||||
|
||||
$template.find('span[data-property="id"]').text(this.id).attr('data-value', this.id);
|
||||
if (this.imageUrl === null) {
|
||||
$template.find('span[data-property="image-or-font"]').html('<i class="' + escape(this.fontIcon) + '"></i>');
|
||||
} else {
|
||||
$template.find('span[data-property="image-or-font"]').text(this.imageUrl);
|
||||
}
|
||||
|
||||
$template.find('span[data-property="url"]').text(this.url);
|
||||
|
||||
var text = '';
|
||||
$.each(this.text, function(key, value) {
|
||||
text += '<li><b>' + escape(key) + ':</b> ' + escape(value) + '</li>';
|
||||
});
|
||||
$template.find('ul[data-property="text"]').html(text);
|
||||
|
||||
var subtext = '-';
|
||||
if (this.place === 1) {
|
||||
subtext = '';
|
||||
$.each(this.subtext, function(key, value) {
|
||||
subtext += '<li><b>' + escape(key) + ':</b> ' + escape(value) + '</li>';
|
||||
});
|
||||
}
|
||||
$template.find('ul[data-property="subtext"]').html(subtext);
|
||||
|
||||
if (first) {
|
||||
$template.find('[data-direction="up"]').css('visibility', 'hidden');
|
||||
first = false;
|
||||
}
|
||||
|
||||
$tableBody.append($template);
|
||||
|
||||
elements[this.id] = this;
|
||||
|
||||
addedElementToPlace = true;
|
||||
lastElement = this;
|
||||
});
|
||||
|
||||
if (lastElement) {
|
||||
//-- Hide the down arrow on the last element
|
||||
$('[data-value="' + lastElement.id + '"]').parent().parent()
|
||||
.find('[data-direction="down"]').css('visibility', 'hidden');
|
||||
}
|
||||
},
|
||||
error: function(data) {
|
||||
mfhAlert.errorWithLog(mfhLang.text('failed_to_load_custom_nav_elements'), data.responseJSON);
|
||||
console.error(data);
|
||||
},
|
||||
complete: function() {
|
||||
$('#overlay').hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function escape(str) {
|
||||
var div = document.createElement('div');
|
||||
div.appendChild(document.createTextNode(str));
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function bindEditModal() {
|
||||
$(document).on('click', '[data-action="edit"]', function() {
|
||||
var element = elements[$(this).parent().parent().find('[data-property="id"]').text()];
|
||||
var $modal = $('#nav-element-modal');
|
||||
|
||||
$modal.find('#edit-label').show();
|
||||
$modal.find('#create-label').hide();
|
||||
$modal.find('select[name="place"]').val(element.place);
|
||||
$modal.find('input[name="id"]').val(element.id);
|
||||
$modal.find('input[name="url"]').val(element.url);
|
||||
var $textLanguages = $modal.find('[data-text-language]');
|
||||
$.each($textLanguages, function() {
|
||||
var language = $(this).data('text-language');
|
||||
|
||||
$(this).val(element.text[language]);
|
||||
});
|
||||
|
||||
var $subtextLanguages = $modal.find('[data-subtext-language]');
|
||||
$.each($subtextLanguages, function() {
|
||||
var language = $(this).data('subtext-language');
|
||||
|
||||
$(this).val(element.subtext[language]);
|
||||
});
|
||||
|
||||
if (element.place === 1) {
|
||||
$('#subtext').show();
|
||||
} else {
|
||||
$('#subtext').hide();
|
||||
}
|
||||
|
||||
if (element.imageUrl !== null) {
|
||||
$modal.find('select[name="image-type"]').val('image-url');
|
||||
$modal.find('input[name="image-url"]').val(element.imageUrl);
|
||||
$modal.find('#font-icon-group').hide();
|
||||
$modal.find('#image-url-group').show();
|
||||
} else {
|
||||
$modal.find('select[name="image-type"]').val('font-icon');
|
||||
$('[data-toggle="nav-iconpicker"]').iconpicker('setIcon', element.fontIcon);
|
||||
$modal.find('#font-icon-group').show();
|
||||
$modal.find('#image-url-group').hide();
|
||||
}
|
||||
|
||||
|
||||
$modal.modal('show');
|
||||
});
|
||||
}
|
||||
|
||||
function bindCreateModal() {
|
||||
$('#create-button').click(function() {
|
||||
var $modal = $('#nav-element-modal');
|
||||
$modal.find('#edit-label').hide();
|
||||
$modal.find('#create-label').show();
|
||||
$modal.find('select[name="place"]').val(1);
|
||||
$modal.find('input[name="id"]').val(-1);
|
||||
var $textLanguages = $modal.find('[data-text-language]');
|
||||
$.each($textLanguages, function() {
|
||||
var language = $(this).data('text-language');
|
||||
|
||||
$(this).val('');
|
||||
});
|
||||
|
||||
var $subtextLanguages = $modal.find('[data-subtext-language]');
|
||||
$.each($subtextLanguages, function() {
|
||||
var language = $(this).data('subtext-language');
|
||||
|
||||
$(this).val('');
|
||||
});
|
||||
|
||||
$('#subtext').show();
|
||||
|
||||
$modal.find('select[name="image-type"]').val('image-url');
|
||||
$modal.find('input[name="image-url"]').val('');
|
||||
$modal.find('#font-icon-group').hide();
|
||||
$modal.find('#image-url-group').show();
|
||||
$modal.find('input[name="url"]').val('');
|
||||
|
||||
$modal.modal('show');
|
||||
});
|
||||
}
|
||||
|
||||
function bindDeleteButton() {
|
||||
$(document).on('click', '[data-action="delete"]', function() {
|
||||
$('#overlay').show();
|
||||
|
||||
var heskUrl = $('#heskUrl').text();
|
||||
var element = elements[$(this).parent().parent().find('[data-property="id"]').text()];
|
||||
|
||||
$.ajax({
|
||||
method: 'DELETE',
|
||||
url: heskUrl + '/api/v1-internal/custom-navigation/' + element.id,
|
||||
headers: { 'X-Internal-Call': true },
|
||||
success: function() {
|
||||
mfhAlert.success(mfhLang.text('custom_nav_element_deleted'));
|
||||
loadTable();
|
||||
},
|
||||
error: function(data) {
|
||||
$('#overlay').hide();
|
||||
mfhAlert.errorWithLog(mfhLang.text('error_deleting_custom_nav_element'), data.responseJSON);
|
||||
console.error(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function bindSortButtons() {
|
||||
$(document).on('click', '[data-action="sort"]', function() {
|
||||
$('#overlay').show();
|
||||
var heskUrl = $('#heskUrl').text();
|
||||
var direction = $(this).data('direction');
|
||||
var element = elements[$(this).parent().parent().find('[data-property="id"]').text()];
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: heskUrl + '/api/v1-internal/custom-navigation/' + element.id + '/sort/' + direction,
|
||||
headers: { 'X-Internal-Call': true },
|
||||
success: function() {
|
||||
loadTable();
|
||||
},
|
||||
error: function(data) {
|
||||
mfhAlert.errorWithLog(mfhLang.text('error_sorting_custom_nav_elements'), data.responseJSON);
|
||||
console.error(data);
|
||||
$('#overlay').hide();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue