From 8db64d903dc06be48917618772c93629bdf12a42 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sat, 6 May 2017 22:17:22 -0400 Subject: [PATCH 01/18] Getting started on custom nav elements --- admin/manage_custom_nav_elements.php | 169 +++++++++++++++++++++++ install/mods-for-hesk/sql/installSql.php | 13 ++ 2 files changed, 182 insertions(+) create mode 100644 admin/manage_custom_nav_elements.php diff --git a/admin/manage_custom_nav_elements.php b/admin/manage_custom_nav_elements.php new file mode 100644 index 00000000..4b36b55c --- /dev/null +++ b/admin/manage_custom_nav_elements.php @@ -0,0 +1,169 @@ + +
+
+
+
+

+ Custom Nav Menu Elements[!] +

+
+ +
+
+
+ +
+
+
+
+

EDIT CUSTOM NAV ELEMENT[!]

+
+
+
+
+
+
+
+
+ +
+
+ $value) { + $languages[$key] = $hesk_settings['languages'][$key]['folder']; + } + + $customElementsRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "custom_nav_element`"); + ?> + + + + + + + + + + + + + '; + } + + while ($row = hesk_dbFetchAssoc($customElementsRs)): + $localizedTextRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "custom_nav_element_to_text` + WHERE `nav_element_id` = " . intval($row['id'])); + $languageText = array(); + while ($textRow = hesk_dbFetchAssoc($localizedTextRs)) { + $languageText[$textRow['language']] = $textRow; + } ?> + + + + + + + + + + +
IDTextSubtextImage URL / Font IconPlaceActions
No custom navigation elements
+
    + $value): ?> +
  • + : + +
  • + +
+
+
    + $value): ?> +
  • + : + +
  • + +
+
+ '; + } ?> + + + EDIT, DELETE
+
+
+
+
+
+
+ Date: Mon, 8 May 2017 21:56:30 -0400 Subject: [PATCH 02/18] Getting more work done on custom navigation --- admin/manage_custom_nav_elements.php | 73 +++++++++++-------- api/ApplicationContext.php | 9 +++ .../Navigation/CustomNavElement.php | 24 ++++++ .../Navigation/CustomNavElementHandler.php | 32 ++++++++ .../Navigation/CustomNavElementPlace.php | 10 +++ api/BusinessLogic/Security/UserContext.php | 1 - .../Navigation/CustomNavElementController.php | 17 +++++ .../Navigation/CustomNavElementGateway.php | 22 ++++++ api/index.php | 2 + language/en/text.php | 1 + 10 files changed, 159 insertions(+), 32 deletions(-) create mode 100644 api/BusinessLogic/Navigation/CustomNavElement.php create mode 100644 api/BusinessLogic/Navigation/CustomNavElementHandler.php create mode 100644 api/BusinessLogic/Navigation/CustomNavElementPlace.php create mode 100644 api/Controllers/Navigation/CustomNavElementController.php create mode 100644 api/DataAccess/Navigation/CustomNavElementGateway.php diff --git a/admin/manage_custom_nav_elements.php b/admin/manage_custom_nav_elements.php index 4b36b55c..d1d78ae5 100644 --- a/admin/manage_custom_nav_elements.php +++ b/admin/manage_custom_nav_elements.php @@ -16,15 +16,7 @@ hesk_session_start(); hesk_dbConnect(); hesk_isLoggedIn(); -//hesk_checkPermission('can_man_email_tpl'); - -// Are we performing an action? -$showEditPanel = false; -if (isset($_GET['action'])) { - if ($_GET['action'] == 'edit') { - $showEditPanel = true; - } -} +//hesk_checkPermission('can_man_custom_nav'); // Are we saving? if (isset($_POST['action'])) { @@ -52,21 +44,6 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
- -
-
-
-
-

EDIT CUSTOM NAV ELEMENT[!]

-
-
-
-
-
-
-
-
-
- EDIT, DELETE + + + + + + + + @@ -158,12 +144,37 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
+ +
+
+

+ Edit Custom Navigation Menu Element +

+
+ +
+
+
+
+
+
+
+ + get = array(); @@ -50,6 +55,10 @@ class ApplicationContext { // API Checker $this->get[ApiChecker::class] = new ApiChecker($this->get[ModsForHeskSettingsGateway::class]); + // Custom Navigation + $this->get[CustomNavElementGateway::class] = new CustomNavElementGateway(); + $this->get[CustomNavElementHandler::class] = new CustomNavElementHandler($this->get[CustomNavElementGateway::class]); + // Logging $this->get[LoggingGateway::class] = new LoggingGateway(); diff --git a/api/BusinessLogic/Navigation/CustomNavElement.php b/api/BusinessLogic/Navigation/CustomNavElement.php new file mode 100644 index 00000000..d720d6b7 --- /dev/null +++ b/api/BusinessLogic/Navigation/CustomNavElement.php @@ -0,0 +1,24 @@ +customNavElementGateway = $customNavElementGateway; + } + + + function getAllCustomNavElements($heskSettings) { + return $this->customNavElementGateway->getAllCustomNavElements($heskSettings); + } + + function deleteCustomNavElement() { + + } + + function saveCustomNavElement() { + + } + + function createCustomNavElement() { + + } +} \ No newline at end of file diff --git a/api/BusinessLogic/Navigation/CustomNavElementPlace.php b/api/BusinessLogic/Navigation/CustomNavElementPlace.php new file mode 100644 index 00000000..3114fdc7 --- /dev/null +++ b/api/BusinessLogic/Navigation/CustomNavElementPlace.php @@ -0,0 +1,10 @@ +id = intval($dataRow['id']); $userContext->username = $dataRow['user']; diff --git a/api/Controllers/Navigation/CustomNavElementController.php b/api/Controllers/Navigation/CustomNavElementController.php new file mode 100644 index 00000000..a36bfe78 --- /dev/null +++ b/api/Controllers/Navigation/CustomNavElementController.php @@ -0,0 +1,17 @@ +get[CustomNavElementHandler::class]; + + output($handler->getAllCustomNavElements($hesk_settings)); + } +} \ No newline at end of file diff --git a/api/DataAccess/Navigation/CustomNavElementGateway.php b/api/DataAccess/Navigation/CustomNavElementGateway.php new file mode 100644 index 00000000..3e025f36 --- /dev/null +++ b/api/DataAccess/Navigation/CustomNavElementGateway.php @@ -0,0 +1,22 @@ +init(); + + $rs = hesk_dbQuery("SELECT `t2`.`id` AS `xref_id`, `t2`.*, `t1`.* 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`"); + + while ($row = hesk_dbFetchAssoc($rs)) { + var_dump($row); + } + + $this->close(); + } +} \ No newline at end of file diff --git a/api/index.php b/api/index.php index 92e87d99..8c34cb35 100644 --- a/api/index.php +++ b/api/index.php @@ -186,6 +186,8 @@ Link::all(array( /* Internal use only routes */ // Resend email response '/v1-internal/staff/tickets/{i}/resend-email' => \Controllers\Tickets\ResendTicketEmailToCustomerController::class, + // Custom Navigation + '/v1-internal/custom-navigation' => \Controllers\Navigation\CustomNavElementController::class . '::getAll', // Any URL that doesn't match goes to the 404 handler '404' => 'handle404' diff --git a/language/en/text.php b/language/en/text.php index 18aca4be..6a03a541 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -52,6 +52,7 @@ $hesklang['resend_email_notification'] = 'Re-send Email Notification'; $hesklang['email_notification_sent'] = 'Email notification sent!'; $hesklang['email_notification_resend_failed'] = 'Error occurred when trying to send notification email.'; $hesklang['edit_category'] = 'Edit Category'; +$hesklang['custom_nav_element_deleted'] = 'Custom Navigation Element Deleted!'; // ADDED OR MODIFIED IN Mods for HESK 3.0.0 $hesklang['you_have_x_messages'] = 'You have %s new %s'; // %s: Number of new messages, "message" or "messages", depending on # From d06d1688502be8269e6d1dc3316eaa01852c640b Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Tue, 9 May 2017 22:00:01 -0400 Subject: [PATCH 03/18] Finished up retrieving custom nav elements --- .../Navigation/CustomNavElementGateway.php | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/api/DataAccess/Navigation/CustomNavElementGateway.php b/api/DataAccess/Navigation/CustomNavElementGateway.php index 3e025f36..4beaf021 100644 --- a/api/DataAccess/Navigation/CustomNavElementGateway.php +++ b/api/DataAccess/Navigation/CustomNavElementGateway.php @@ -3,20 +3,49 @@ namespace DataAccess\Navigation; +use BusinessLogic\Navigation\CustomNavElement; use DataAccess\CommonDao; class CustomNavElementGateway extends CommonDao { function getAllCustomNavElements($heskSettings) { $this->init(); - $rs = hesk_dbQuery("SELECT `t2`.`id` AS `xref_id`, `t2`.*, `t1`.* FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_nav_element` AS `t1` + $columns = '`t1`.`id`, `t1`.`image_url`, `t1`.`font_icon`, `t1`.`place`, `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`"); + $elements = array(); + $element = null; + $previousId = -1; while ($row = hesk_dbFetchAssoc($rs)) { - var_dump($row); + $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->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; } } \ No newline at end of file From 6e72662a1bf3e01d524e44cb92a93c7b16191682 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Thu, 11 May 2017 22:00:51 -0400 Subject: [PATCH 04/18] Wrote the custom nav element api --- .../Navigation/CustomNavElement.php | 4 +- .../Navigation/CustomNavElementHandler.php | 19 +++- .../Navigation/CustomNavElementController.php | 72 +++++++++++- .../Navigation/CustomNavElementGateway.php | 103 +++++++++++++++++- api/index.php | 4 +- 5 files changed, 193 insertions(+), 9 deletions(-) diff --git a/api/BusinessLogic/Navigation/CustomNavElement.php b/api/BusinessLogic/Navigation/CustomNavElement.php index d720d6b7..2e0e7261 100644 --- a/api/BusinessLogic/Navigation/CustomNavElement.php +++ b/api/BusinessLogic/Navigation/CustomNavElement.php @@ -7,10 +7,10 @@ class CustomNavElement { /* @var $id int*/ public $id; - /* @var $text string[string] */ + /* @var $text string[] */ public $text; - /* @var $subtext string[string]|null */ + /* @var $subtext string[]|null */ public $subtext; /* @var $imageUrl string|null */ diff --git a/api/BusinessLogic/Navigation/CustomNavElementHandler.php b/api/BusinessLogic/Navigation/CustomNavElementHandler.php index 0a159116..4a8cad62 100644 --- a/api/BusinessLogic/Navigation/CustomNavElementHandler.php +++ b/api/BusinessLogic/Navigation/CustomNavElementHandler.php @@ -3,6 +3,7 @@ namespace BusinessLogic\Navigation; // TODO Test! +use BusinessLogic\Exceptions\ApiFriendlyException; use DataAccess\Navigation\CustomNavElementGateway; class CustomNavElementHandler { @@ -18,15 +19,25 @@ class CustomNavElementHandler { return $this->customNavElementGateway->getAllCustomNavElements($heskSettings); } - function deleteCustomNavElement() { + function getCustomNavElement($id, $heskSettings) { + $elements = $this->getAllCustomNavElements($heskSettings); - } + if (isset($elements[$id])) { + return $elements[$id]; + } - function saveCustomNavElement() { + throw new ApiFriendlyException("Custom nav element {$id} not found!", "Element Not Found", 404); + } + function deleteCustomNavElement($id, $heskSettings) { + $this->customNavElementGateway->deleteCustomNavElement($id, $heskSettings); } - function createCustomNavElement() { + function saveCustomNavElement($element, $heskSettings) { + $this->customNavElementGateway->saveCustomNavElement($element, $heskSettings); + } + function createCustomNavElement($element, $heskSettings) { + return $this->customNavElementGateway->createCustomNavElement($element, $heskSettings); } } \ No newline at end of file diff --git a/api/Controllers/Navigation/CustomNavElementController.php b/api/Controllers/Navigation/CustomNavElementController.php index a36bfe78..2387e506 100644 --- a/api/Controllers/Navigation/CustomNavElementController.php +++ b/api/Controllers/Navigation/CustomNavElementController.php @@ -3,15 +3,85 @@ namespace Controllers\Navigation; +use BusinessLogic\Helpers; +use BusinessLogic\Navigation\CustomNavElement; use BusinessLogic\Navigation\CustomNavElementHandler; +use Controllers\InternalApiController; +use Controllers\JsonRetriever; -class CustomNavElementController { +class CustomNavElementController extends InternalApiController { static function getAll() { global $applicationContext, $hesk_settings; + self::checkForInternalUseOnly(); + /* @var $handler CustomNavElementHandler */ $handler = $applicationContext->get[CustomNavElementHandler::class]; output($handler->getAllCustomNavElements($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'); + + return $element; + } } \ No newline at end of file diff --git a/api/DataAccess/Navigation/CustomNavElementGateway.php b/api/DataAccess/Navigation/CustomNavElementGateway.php index 4beaf021..77671891 100644 --- a/api/DataAccess/Navigation/CustomNavElementGateway.php +++ b/api/DataAccess/Navigation/CustomNavElementGateway.php @@ -17,13 +17,15 @@ class CustomNavElementGateway extends CommonDao { ON `t1`.`id` = `t2`.`nav_element_id`"); $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; + $elements[$element->id] = $element; } $element = new CustomNavElement(); $element->id = $id; @@ -48,4 +50,103 @@ class CustomNavElementGateway extends CommonDao { 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}, + `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(); + + $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`) + VALUES ({$imageUrl}, {$fontIcon}, " . intval($element->place) . ")"); + + $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; + } } \ No newline at end of file diff --git a/api/index.php b/api/index.php index 8c34cb35..9404b9c2 100644 --- a/api/index.php +++ b/api/index.php @@ -187,7 +187,9 @@ Link::all(array( // Resend email response '/v1-internal/staff/tickets/{i}/resend-email' => \Controllers\Tickets\ResendTicketEmailToCustomerController::class, // Custom Navigation - '/v1-internal/custom-navigation' => \Controllers\Navigation\CustomNavElementController::class . '::getAll', + '/v1-internal/custom-navigation/all' => \Controllers\Navigation\CustomNavElementController::class . '::getAll', + '/v1-internal/custom-navigation' => \Controllers\Navigation\CustomNavElementController::class, + '/v1-internal/custom-navigation/{i}' => \Controllers\Navigation\CustomNavElementController::class, // Any URL that doesn't match goes to the 404 handler '404' => 'handle404' From 6b05ee31ab76e7cc53bd99c315bb0b34cfd98a94 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Fri, 12 May 2017 13:11:28 -0400 Subject: [PATCH 05/18] Working on incorporating the API into the page --- admin/manage_custom_nav_elements.php | 128 ++++-------------- api/Controllers/InternalApiController.php | 7 + .../Navigation/CustomNavElementController.php | 2 +- internal-api/js/manage-custom-nav-elements.js | 50 +++++++ 4 files changed, 82 insertions(+), 105 deletions(-) create mode 100644 internal-api/js/manage-custom-nav-elements.js diff --git a/admin/manage_custom_nav_elements.php b/admin/manage_custom_nav_elements.php index d1d78ae5..7d06e59c 100644 --- a/admin/manage_custom_nav_elements.php +++ b/admin/manage_custom_nav_elements.php @@ -4,6 +4,7 @@ define('IN_SCRIPT', 1); define('HESK_PATH', '../'); define('PAGE_TITLE', 'ADMIN_CUSTOM_NAV_ELEMENTS'); define('MFH_PAGE_LAYOUT', 'TOP_ONLY'); +define('EXTRA_JS', ''); /* Get all the required files and functions */ require(HESK_PATH . 'hesk_settings.inc.php'); @@ -18,12 +19,6 @@ hesk_isLoggedIn(); //hesk_checkPermission('can_man_custom_nav'); -// Are we saving? -if (isset($_POST['action'])) { - if ($_POST['action'] == 'save') { - save(); - } -} /* Print header */ require_once(HESK_PATH . 'inc/headerAdmin.inc.php'); @@ -68,113 +63,38 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php'); Actions - - No custom navigation elements'; - } + - while ($row = hesk_dbFetchAssoc($customElementsRs)): - $localizedTextRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "custom_nav_element_to_text` - WHERE `nav_element_id` = " . intval($row['id'])); - $languageText = array(); - while ($textRow = hesk_dbFetchAssoc($localizedTextRs)) { - $languageText[$textRow['language']] = $textRow; - } ?> - - - -
    - $value): ?> -
  • - : - -
  • - -
- - -
    - $value): ?> -
  • - : - -
  • - -
- - - '; - } ?> - - - - - - - - - - - - - - - -
-
-

- Edit Custom Navigation Menu Element -

-
- -
-
-
-
-
-
-
- -