mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-22 09:22:22 +00:00
- Added new function generateJSModulesInclude to application/helpers/hlp_header_helper.php
- Added entry "customJSModules" to the application/views/templates/FHC-Footer.php to be passed to the generateJSModulesInclude function to generate JS modules tags - The new VUE components are making use of the JS import and export functionalities
This commit is contained in:
@@ -149,6 +149,31 @@ function generateJSsInclude($JSs)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates tags for the javascript modules you want to include, the parameter could by a string or an array of strings
|
||||
*/
|
||||
function generateJSModulesInclude($JSModules)
|
||||
{
|
||||
$jsInclude = '<script type="module" src="%s"></script>';
|
||||
|
||||
$ci =& get_instance();
|
||||
$cachetoken = '?'.$ci->config->item('fhcomplete_build_version');
|
||||
|
||||
if (isset($JSModules))
|
||||
{
|
||||
$tmpJSs = is_array($JSModules) ? $JSModules : array($JSModules);
|
||||
|
||||
for ($tmpJSsCounter = 0; $tmpJSsCounter < count($tmpJSs); $tmpJSsCounter++)
|
||||
{
|
||||
$toPrint = sprintf($jsInclude, base_url($tmpJSs[$tmpJSsCounter].$cachetoken)).PHP_EOL;
|
||||
|
||||
if ($tmpJSsCounter > 0) $toPrint = "\t\t".$toPrint;
|
||||
|
||||
echo $toPrint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates all the includes needed by the Addons
|
||||
*/
|
||||
@@ -180,3 +205,4 @@ function generateBackwardCompatibleJSMsIe($js)
|
||||
echo ' <script type="text/javascript" src="'.$js.'"></script>'."\n";
|
||||
echo "<![endif]-->\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
'global' => array('mailAnXversandt'),
|
||||
'ui' => array('bitteEintragWaehlen')
|
||||
),
|
||||
'customJSs' => array('public/js/apps/LogsViewer.js')
|
||||
'customJSModules' => array('public/js/apps/LogsViewer.js')
|
||||
);
|
||||
|
||||
$this->load->view('templates/FHC-Header', $includesArray);
|
||||
@@ -36,6 +36,50 @@
|
||||
<div>
|
||||
<!-- Filter component -->
|
||||
<core-filter-cmpt filter-type="LogsViewer" @nw-new-entry="newSideMenuEntryHandler"></core-filter-cmpt>
|
||||
<!--
|
||||
'datasetRepresentation' => 'tablesorter',
|
||||
'columnsAliases' => array(
|
||||
'Log id',
|
||||
'Request id',
|
||||
'Execution time',
|
||||
'Executed by',
|
||||
'Producer',
|
||||
'Data',
|
||||
'Webservice type'
|
||||
),
|
||||
'formatRow' => function($datasetRaw) {
|
||||
|
||||
$datasetRaw->ExecutionTime = date_format(date_create($datasetRaw->ExecutionTime), 'd.m.Y H:i:s:u');
|
||||
|
||||
return $datasetRaw;
|
||||
},
|
||||
'markRow' => function($datasetRaw) {
|
||||
|
||||
$mark = '';
|
||||
|
||||
if (strpos($datasetRaw->RequestId, 'error') != false)
|
||||
{
|
||||
$mark = 'text-red';
|
||||
}
|
||||
|
||||
if (strpos($datasetRaw->RequestId, 'info') != false)
|
||||
{
|
||||
$mark = 'text-green';
|
||||
}
|
||||
|
||||
if (strpos($datasetRaw->RequestId, 'warning') != false)
|
||||
{
|
||||
$mark = 'text-orange';
|
||||
}
|
||||
|
||||
if (strpos($datasetRaw->RequestId, 'debug') != false)
|
||||
{
|
||||
$mark = 'text-info';
|
||||
}
|
||||
|
||||
return $mark;
|
||||
}
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
// By default set the parameters to null
|
||||
$customJSs = isset($customJSs) ? $customJSs : null;
|
||||
$customJSModules = isset($customJSModules) ? $customJSModules : null;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
// Javascripts
|
||||
@@ -118,24 +119,15 @@
|
||||
// NOTE: to be used only if you know what you are doing!
|
||||
if ($bootstrapper === true) generateJSsInclude('public/js/bootstrapper.js');
|
||||
|
||||
// VUE Navigation Component JS
|
||||
if ($navigationcomponent === true) generateJSsInclude('public/js/components/Navigation.js');
|
||||
|
||||
// NavigationWidget JS
|
||||
if ($navigationwidget === true) generateJSsInclude('public/js/NavigationWidget.js');
|
||||
|
||||
// VUE Filter Component JS
|
||||
if ($filtercomponent === true) generateJSsInclude('public/js/components/Filter.js');
|
||||
|
||||
// FilterWidget JS
|
||||
if ($filterwidget === true) generateJSsInclude('public/js/FilterWidget.js');
|
||||
|
||||
// PhrasesLib JS
|
||||
if ($phrases != null) generateJSsInclude('public/js/PhrasesLib.js');
|
||||
|
||||
// VUE Table Component JS
|
||||
if ($tablecomponent === true) generateJSsInclude('public/js/components/Table.js');
|
||||
|
||||
// TableWidget JS
|
||||
if ($tablewidget === true) generateJSsInclude('public/js/TableWidget.js');
|
||||
|
||||
@@ -149,6 +141,7 @@
|
||||
// Eventually required JS
|
||||
// NOTE: keep it as the latest
|
||||
generateJSsInclude($customJSs);
|
||||
generateJSModulesInclude($customJSModules);
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import {CoreFilterCmpt} from '../components/Filter.js';
|
||||
import {CoreNavigationCmpt} from '../components/Navigation.js';
|
||||
|
||||
const logsViewerApp = Vue.createApp({
|
||||
data() {
|
||||
return {
|
||||
|
||||
+314
-48
@@ -1,15 +1,18 @@
|
||||
const CoreFilterCmpt = {
|
||||
export const CoreFilterCmpt = {
|
||||
emits: ['nwNewEntry'],
|
||||
data() {
|
||||
return {
|
||||
fields: null,
|
||||
fieldsToDisplay: null,
|
||||
dataset: null,
|
||||
selectedFields: null
|
||||
selectedFields: null,
|
||||
notSelectedFields: null,
|
||||
filterFields: null,
|
||||
notFilterFields: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.fetchFilterData();
|
||||
this.fetchFilterMenuData();
|
||||
this._fetchFilterData();
|
||||
},
|
||||
updated() {
|
||||
let filterCmptTablesorter = $("#filterTableDataset");
|
||||
@@ -36,72 +39,179 @@ const CoreFilterCmpt = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchFilterData() {
|
||||
saveCustomFilter(el) {
|
||||
FHC_AjaxClient.ajaxCallPost(
|
||||
"components/Filter/saveCustomFilter",
|
||||
{
|
||||
filterUniqueId: this._getCurrentPage(),
|
||||
filterType: this.filterType,
|
||||
customFilterName: document.getElementById('customFilterName').value
|
||||
},
|
||||
{
|
||||
successCallback: function(data) {console.log(data)}
|
||||
}
|
||||
);
|
||||
},
|
||||
applyFilterFields(el) {
|
||||
let filterFields = [];
|
||||
let filterFieldDivs = document.getElementById('filterFields').getElementsByTagName('div');
|
||||
|
||||
for (let i = 0; i < filterFieldDivs.length; i++)
|
||||
{
|
||||
let filterField = {};
|
||||
|
||||
for (let j = 0; j < filterFieldDivs[i].children.length; j++)
|
||||
{
|
||||
if (filterFieldDivs[i].children[j].name != null)
|
||||
{
|
||||
// Name
|
||||
if (filterFieldDivs[i].children[j].name == 'fieldName')
|
||||
{
|
||||
filterField.name = filterFieldDivs[i].children[j].value;
|
||||
}
|
||||
// Operation
|
||||
if (filterFieldDivs[i].children[j].name == 'operation')
|
||||
{
|
||||
filterField.operation = filterFieldDivs[i].children[j].value;
|
||||
}
|
||||
// Condition
|
||||
if (filterFieldDivs[i].children[j].name == 'condition')
|
||||
{
|
||||
filterField.condition = filterFieldDivs[i].children[j].value;
|
||||
}
|
||||
// Option
|
||||
if (filterFieldDivs[i].children[j].name == 'option')
|
||||
{
|
||||
filterField.option = filterFieldDivs[i].children[j].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterFields.push(filterField);
|
||||
}
|
||||
|
||||
FHC_AjaxClient.ajaxCallPost(
|
||||
"components/Filter/applyFilterFields",
|
||||
{
|
||||
filterUniqueId: this._getCurrentPage(),
|
||||
filterType: this.filterType,
|
||||
filterFields: filterFields
|
||||
},
|
||||
{
|
||||
successCallback: this._fetchFilterData
|
||||
}
|
||||
);
|
||||
},
|
||||
addFilterField(el) {
|
||||
FHC_AjaxClient.ajaxCallPost(
|
||||
"components/Filter/addFilterField",
|
||||
{
|
||||
filterUniqueId: this._getCurrentPage(),
|
||||
filterType: this.filterType,
|
||||
filterField: el.currentTarget.value
|
||||
},
|
||||
{
|
||||
successCallback: this._fetchFilterData
|
||||
}
|
||||
);
|
||||
},
|
||||
addSelectedField(el) {
|
||||
FHC_AjaxClient.ajaxCallPost(
|
||||
"components/Filter/addSelectedField",
|
||||
{
|
||||
filterUniqueId: this._getCurrentPage(),
|
||||
filterType: this.filterType,
|
||||
selectedField: el.currentTarget.value
|
||||
},
|
||||
{
|
||||
successCallback: this._fetchFilterData
|
||||
}
|
||||
);
|
||||
},
|
||||
removeSelectedField(el) {
|
||||
FHC_AjaxClient.ajaxCallPost(
|
||||
"components/Filter/removeSelectedField",
|
||||
{
|
||||
filterUniqueId: this._getCurrentPage(),
|
||||
filterType: this.filterType,
|
||||
selectedField: el.currentTarget.getAttribute('field-to-remove')
|
||||
},
|
||||
{
|
||||
successCallback: this._fetchFilterData
|
||||
}
|
||||
);
|
||||
},
|
||||
removeFilterField(el) {
|
||||
FHC_AjaxClient.ajaxCallPost(
|
||||
"components/Filter/removeFilterField",
|
||||
{
|
||||
filterUniqueId: this._getCurrentPage(),
|
||||
filterType: this.filterType,
|
||||
filterField: el.currentTarget.getAttribute('field-to-remove')
|
||||
},
|
||||
{
|
||||
successCallback: this._fetchFilterData
|
||||
}
|
||||
);
|
||||
},
|
||||
fetchFilterDataById(el) {
|
||||
FHC_AjaxClient.ajaxCallGet(
|
||||
"components/Filter/getFilter",
|
||||
{
|
||||
filterUniqueId: this.getFilterUniqueIdPrefix(),
|
||||
filterType: this.filterType, // props!!
|
||||
filterId: 170
|
||||
filterUniqueId: this._getCurrentPage(),
|
||||
filterType: this.filterType,
|
||||
filter_id: el.currentTarget.getAttribute("href").substring(1)
|
||||
},
|
||||
{
|
||||
successCallback: this.renderTableSorter
|
||||
successCallback: this._render
|
||||
}
|
||||
);
|
||||
},
|
||||
fetchFilterMenuData() {
|
||||
_fetchFilterData() {
|
||||
FHC_AjaxClient.ajaxCallGet(
|
||||
"components/Filter/generateFilterMenu",
|
||||
"components/Filter/getFilter",
|
||||
{
|
||||
filterUniqueId: this.getFilterUniqueIdPrefix(),
|
||||
navigation_page: this.getNavigationPage()
|
||||
filterUniqueId: this._getCurrentPage(),
|
||||
filterType: this.filterType // props!!
|
||||
},
|
||||
{
|
||||
successCallback: this.setSideMenu
|
||||
successCallback: this._render
|
||||
}
|
||||
);
|
||||
},
|
||||
setSideMenu(data) {
|
||||
// Set the menu
|
||||
if (FHC_AjaxClient.hasData(data))
|
||||
{
|
||||
let filters = FHC_AjaxClient.getData(data).filters;
|
||||
let personalFilters = FHC_AjaxClient.getData(data).personalFilters;
|
||||
let filtersArray = [];
|
||||
|
||||
for (let filtersCount = 0; filtersCount < filters.length; filtersCount++)
|
||||
{
|
||||
filtersArray[filtersArray.length] = {
|
||||
link: filters[filtersCount].link,
|
||||
description: filters[filtersCount].desc,
|
||||
sort: filtersCount
|
||||
};
|
||||
}
|
||||
|
||||
this.$emit(
|
||||
'nwNewEntry',
|
||||
[{
|
||||
link: "#",
|
||||
description: "Filters",
|
||||
icon: "filter",
|
||||
children: filtersArray
|
||||
}]
|
||||
);
|
||||
}
|
||||
},
|
||||
getFilterUniqueIdPrefix() {
|
||||
_getCurrentPage: function() {
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.called_path + "/" + FHC_JS_DATA_STORAGE_OBJECT.called_method;
|
||||
},
|
||||
getNavigationPage: function() {
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.called_path + "/" + FHC_JS_DATA_STORAGE_OBJECT.called_method;
|
||||
},
|
||||
renderTableSorter(data) {
|
||||
_render(data) {
|
||||
|
||||
if (FHC_AjaxClient.hasData(data))
|
||||
{
|
||||
this._setFieldsToDisplay(FHC_AjaxClient.getData(data));
|
||||
this.dataset = FHC_AjaxClient.getData(data).dataset;
|
||||
this.fields = FHC_AjaxClient.getData(data).fields;
|
||||
this.selectedFields = FHC_AjaxClient.getData(data).selectedFields;
|
||||
this.notSelectedFields = this.fields.filter(x => this.selectedFields.indexOf(x) === -1);
|
||||
|
||||
this.filterFields = [];
|
||||
let tmpFilterFields = [];
|
||||
for (let i = 0; i < FHC_AjaxClient.getData(data).datasetMetadata.length; i++)
|
||||
{
|
||||
for (let j = 0; j < FHC_AjaxClient.getData(data).filters.length; j++)
|
||||
{
|
||||
if (FHC_AjaxClient.getData(data).datasetMetadata[i].name == FHC_AjaxClient.getData(data).filters[j].name)
|
||||
{
|
||||
let filter = FHC_AjaxClient.getData(data).filters[j];
|
||||
filter.type = FHC_AjaxClient.getData(data).datasetMetadata[i].type;
|
||||
|
||||
this.filterFields.push(filter);
|
||||
tmpFilterFields.push(filter.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.notFilterFields = this.fields.filter(x => tmpFilterFields.indexOf(x) === -1);
|
||||
this._setFieldsToDisplay(FHC_AjaxClient.getData(data));
|
||||
this._setSideMenu(FHC_AjaxClient.getData(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -134,9 +244,165 @@ const CoreFilterCmpt = {
|
||||
}
|
||||
|
||||
this.fieldsToDisplay = arrayFieldsToDisplay;
|
||||
},
|
||||
_setSideMenu(data) {
|
||||
// Set the menu
|
||||
let filters = data.sideMenu.filters;
|
||||
let personalFilters = data.sideMenu.personalFilters;
|
||||
let filtersArray = [];
|
||||
|
||||
for (let filtersCount = 0; filtersCount < filters.length; filtersCount++)
|
||||
{
|
||||
let link = filters[filtersCount].link;
|
||||
|
||||
if (link == null) link = '#';
|
||||
|
||||
filtersArray[filtersArray.length] = {
|
||||
link: link + filters[filtersCount].filter_id,
|
||||
description: filters[filtersCount].desc,
|
||||
sort: filtersCount,
|
||||
onClickCall: this.fetchFilterDataById
|
||||
};
|
||||
}
|
||||
|
||||
this.$emit(
|
||||
'nwNewEntry',
|
||||
[{
|
||||
link: "#",
|
||||
description: "Filters",
|
||||
icon: "filter",
|
||||
children: filtersArray
|
||||
}]
|
||||
);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="card filter-filter-options">
|
||||
<div class="card-header filter-header-title" data-bs-toggle="collapse" data-bs-target="#collapseFilterHeader">
|
||||
Filter options
|
||||
</div>
|
||||
<div id="collapseFilterHeader" class="card-body collapse">
|
||||
<!-- Filter fields options -->
|
||||
<div class="filter-options-div">
|
||||
<div class="filter-dnd-area">
|
||||
<template v-for="fieldToDisplay in fieldsToDisplay">
|
||||
<span class="filter-dnd-object">
|
||||
{{ fieldToDisplay }}
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
v-bind:field-to-remove="fieldToDisplay"
|
||||
@click=removeSelectedField>
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
<select class="form-select form-select-sm" @change=addSelectedField>
|
||||
<option value="">Select a field to be displayed...</option>
|
||||
<template v-for="hiddenField in notSelectedFields">
|
||||
<option v-bind:value="hiddenField">{{ hiddenField }}</option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Filter options -->
|
||||
<div class="filter-options-div">
|
||||
<div>
|
||||
<select class="form-select form-select-sm" @change=addFilterField>
|
||||
<option value="">Add a field to the filter...</option>
|
||||
<template v-for="notFilterField in notFilterFields">
|
||||
<option v-bind:value="notFilterField">{{ notFilterField }}</option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
<div id="filterFields" class="filter-filter-fields">
|
||||
<template v-for="filterField in filterFields">
|
||||
<!-- Numeric -->
|
||||
<div v-if="filterField.type.toLowerCase().indexOf('int') >= 0" class="input-group mb-3">
|
||||
<input type="hidden" name="fieldName" v-bind:value="filterField.name">
|
||||
<span class="input-group-text">{{ filterField.name }}</span>
|
||||
<select class="form-select form-select-sm" name="operation">
|
||||
<option value="equal">Equal</option>
|
||||
<option value="nequal">Not equal</option>
|
||||
<option value="gt">Greater then</option>
|
||||
<option value="lt">Less then</option>
|
||||
</select>
|
||||
<input type="number" class="form-control" v-bind:value="filterField.condition" name="condition">
|
||||
<button
|
||||
class="btn btn-sm btn-outline-dark"
|
||||
type="button"
|
||||
v-bind:field-to-remove="filterField.name"
|
||||
@click=removeFilterField>
|
||||
 X 
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Text -->
|
||||
<div
|
||||
v-if="filterField.type.toLowerCase().indexOf('varchar') >= 0
|
||||
|| filterField.type.toLowerCase().indexOf('text') >= 0
|
||||
|| filterField.type.toLowerCase().indexOf('bpchar') >= 0"
|
||||
class="input-group mb-3">
|
||||
<input type="hidden" name="fieldName" v-bind:value="filterField.name">
|
||||
<span class="input-group-text">{{ filterField.name }}</span>
|
||||
<select class="form-select form-select-sm" name="operation">
|
||||
<option value="contains">Conrains</option>
|
||||
<option value="ncontains">Does not contain</option>
|
||||
</select>
|
||||
<input type="text" class="form-control" v-bind:value="filterField.condition" name="condition">
|
||||
<button
|
||||
class="btn btn-sm btn-outline-dark"
|
||||
type="button"
|
||||
v-bind:field-to-remove="filterField.name"
|
||||
@click=removeFilterField>
|
||||
 X 
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Timestamp and date -->
|
||||
<div
|
||||
v-if="filterField.type.toLowerCase().indexOf('timestamp') >= 0
|
||||
|| filterField.type.toLowerCase().indexOf('date') >= 0"
|
||||
class="input-group mb-3">
|
||||
<input type="hidden" name="fieldName" v-bind:value="filterField.name">
|
||||
<span class="input-group-text">{{ filterField.name }}</span>
|
||||
<select class="form-select form-select-sm" name="operation">
|
||||
<option value="gt">Greater then</option>
|
||||
<option value="lt">Less then</option>
|
||||
<option value="set">Is set</option>
|
||||
<option value="nset">Is not set</option>
|
||||
</select>
|
||||
<input type="number" class="form-control" v-bind:value="filterField.condition" name="condition">
|
||||
<select class="form-select form-select-sm" name="option">
|
||||
<option value="minutes">Minutes</option>
|
||||
<option value="hours">Hours</option>
|
||||
<option value="days">Days</option>
|
||||
<option value="months">Months</option>
|
||||
</select>
|
||||
<button
|
||||
class="btn btn-sm btn-outline-dark"
|
||||
type="button"
|
||||
v-bind:field-to-remove="filterField.name"
|
||||
@click=removeFilterField>
|
||||
 X 
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="btn btn-sm btn-outline-dark" @click=applyFilterFields>Apply changes</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter save options -->
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" placeholder="Custom filter name" id="customFilterName">
|
||||
<button type="button" class="btn btn-outline-secondary" @click=saveCustomFilter>Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="tablesorter table-bordered table-responsive" id="filterTableDataset">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const CoreNavigationCmpt = {
|
||||
export const CoreNavigationCmpt = {
|
||||
data() {
|
||||
return {
|
||||
headerMenu: {},
|
||||
@@ -76,7 +76,7 @@ const CoreNavigationCmpt = {
|
||||
<template v-for="header in headerMenuEntries">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link header-menu-link-entry" v-bind:data-bs-toggle="this.getDataBsToggle(header)" v-bind:class="{ 'dropdown-toggle': header.children }" v-bind:href="header.link">
|
||||
<i class="fa-solid" v-bind:class="'fa-' + header.icon" v-if="header.icon"></i> {{ header.description }}
|
||||
<i class="fa-solid fa-fw header-menu-icon" v-bind:class="'fa-' + header.icon" v-if="header.icon"></i> {{ header.description }}
|
||||
</a>
|
||||
<ul class="dropdown-menu" v-if="header.children">
|
||||
<!-- 2nd level -->
|
||||
@@ -90,18 +90,22 @@ const CoreNavigationCmpt = {
|
||||
</nav>
|
||||
|
||||
<!-- Left side menu -->
|
||||
<nav class="navbar sidebar">
|
||||
<nav class="navbar navbar-left-side">
|
||||
<ul class="navbar-nav">
|
||||
<!-- 1st level -->
|
||||
<template v-for="menu in sideMenuEntries">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" v-bind:href="menu.link">
|
||||
<a class="nav-link left-side-menu-link-entry" v-bind:href="menu.link" @click=menu.onClickCall>
|
||||
<i class="fa fa-fw" v-bind:class="'fa-'+ menu.icon"></i> {{ menu.description }}
|
||||
</a>
|
||||
<ul class="nav-link" v-if="menu.children">
|
||||
<ul class="nav-link left-side-menu-second-level" v-if="menu.children">
|
||||
<!-- 2nd level -->
|
||||
<template v-for="child in menu.children">
|
||||
<li><a class="nav-link" v-bind:href="child.link">{{ child.description }}</a></li>
|
||||
<li>
|
||||
<a class="nav-link left-side-menu-link-entry" v-bind:href="child.link" @click=child.onClickCall>
|
||||
  {{ child.description }}
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user