tab groups
This commit is contained in:
@@ -235,6 +235,7 @@
|
||||
"maintenanceMode": "Only administrators will have access to the system."
|
||||
},
|
||||
"labels": {
|
||||
"Group Tab": "Group Tab",
|
||||
"System": "System",
|
||||
"Locale": "Locale",
|
||||
"Search": "Search",
|
||||
|
||||
@@ -11,8 +11,18 @@
|
||||
<ul class="nav navbar-nav tabs">
|
||||
{{#each tabDefsList}}
|
||||
{{#unless isInMore}}
|
||||
<li data-name="{{name}}" class="not-in-more tab">
|
||||
<a href="{{link}}" class="{{aClassName}}"{{#if color}} style="border-color: {{color}}"{{/if}}>
|
||||
<li data-name="{{name}}" class="not-in-more tab{{#if isGroup}} tab-group dropdown{{/if}}">
|
||||
<a
|
||||
href="{{link}}"
|
||||
class="{{aClassName}}"
|
||||
{{#if color}}
|
||||
style="border-color: {{color}}"
|
||||
{{/if}}
|
||||
{{#if isGroup}}
|
||||
id="nav-tab-group-{{name}}"
|
||||
data-toggle="dropdown"
|
||||
{{/if}}
|
||||
>
|
||||
<span class="short-label"{{#if label}} title="{{label}}"{{/if}}{{#if color}} style="color: {{color}}"{{/if}}>
|
||||
{{#if iconClass}}
|
||||
<span class="{{iconClass}}"></span>
|
||||
@@ -27,17 +37,68 @@
|
||||
<span class="full-label">{{label}}</span>
|
||||
{{/if}}
|
||||
{{#if html}}{{{html}}}{{/if}}
|
||||
|
||||
{{#if isGroup}}
|
||||
<span class="fas fa-caret-right group-caret"><span>
|
||||
{{/if}}
|
||||
</a>
|
||||
{{#if isGroup}}
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="nav-tab-group-{{name}}">
|
||||
{{#each itemList}}
|
||||
<li data-name="{{name}}" class="in-group tab">
|
||||
<a
|
||||
href="{{link}}"
|
||||
class="{{aClassName}}"
|
||||
{{#if color}}
|
||||
style="border-color: {{color}}"
|
||||
{{/if}}
|
||||
{{#if isGroup}}
|
||||
id="nav-tab-group-{{name}}"
|
||||
data-toggle="dropdown"
|
||||
{{/if}}
|
||||
>
|
||||
<span class="short-label"{{#if color}} style="color: {{color}}"{{/if}}>
|
||||
{{#if iconClass}}
|
||||
<span class="{{iconClass}}"></span>
|
||||
{{else}}
|
||||
{{#if colorIconClass}}
|
||||
<span class="{{colorIconClass}}" style="color: {{color}}"></span>
|
||||
{{/if}}
|
||||
<span class="short-label-text"> </span>
|
||||
{{/if}}
|
||||
</span>
|
||||
<span class="full-label">{{label}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/unless}}
|
||||
{{/each}}
|
||||
<li class="dropdown more">
|
||||
<a id="nav-more-tabs-dropdown" class="dropdown-toggle" data-toggle="dropdown" href="#"><span class="fas fa-ellipsis-h more-icon"></span></a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="nav-more-tabs-dropdown">
|
||||
<a
|
||||
id="nav-more-tabs-dropdown"
|
||||
class="dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
href="#"
|
||||
><span class="fas fa-ellipsis-h more-icon"></span></a>
|
||||
<ul class="dropdown-menu more-dropdown-menu" role="menu" aria-labelledby="nav-more-tabs-dropdown">
|
||||
{{#each tabDefsList}}
|
||||
{{#if isInMore}}
|
||||
<li data-name="{{name}}" class="in-more tab{{#if className}} {{className}}{{/if}}">
|
||||
<a href="{{link}}" class="{{aClassName}}"{{#if color}} style="border-color: {{color}}"{{/if}}>
|
||||
<li
|
||||
data-name="{{name}}"
|
||||
class="in-more tab{{#if className}} {{className}}{{/if}}{{#if isGroup}} dropdown tab-group{{/if}}"
|
||||
>
|
||||
<a
|
||||
href="{{link}}"
|
||||
class="{{aClassName}}"
|
||||
{{#if color}} style="border-color: {{color}}"{{/if}}
|
||||
{{#if isGroup}}
|
||||
id="nav-tab-group-{{name}}"
|
||||
data-toggle="dropdown"
|
||||
{{/if}}
|
||||
>
|
||||
<span class="short-label"{{#if color}} style="color: {{color}}"{{/if}}>
|
||||
{{#if iconClass}}
|
||||
<span class="{{iconClass}}"></span>
|
||||
@@ -52,7 +113,42 @@
|
||||
<span class="full-label">{{label}}</span>
|
||||
{{/if}}
|
||||
{{#if html}}{{{html}}}{{/if}}
|
||||
|
||||
{{#if isGroup}}
|
||||
<span class="fas fa-caret-right group-caret"><span>
|
||||
{{/if}}
|
||||
</a>
|
||||
{{#if isGroup}}
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="nav-tab-group-{{name}}">
|
||||
{{#each itemList}}
|
||||
<li data-name="{{name}}" class="in-group tab">
|
||||
<a
|
||||
href="{{link}}"
|
||||
class="{{aClassName}}"
|
||||
{{#if color}}
|
||||
style="border-color: {{color}}"
|
||||
{{/if}}
|
||||
{{#if isGroup}}
|
||||
id="nav-tab-group-{{name}}"
|
||||
data-toggle="dropdown"
|
||||
{{/if}}
|
||||
>
|
||||
<span class="short-label"{{#if color}} style="color: {{color}}"{{/if}}>
|
||||
{{#if iconClass}}
|
||||
<span class="{{iconClass}}"></span>
|
||||
{{else}}
|
||||
{{#if colorIconClass}}
|
||||
<span class="{{colorIconClass}}" style="color: {{color}}"></span>
|
||||
{{/if}}
|
||||
<span class="short-label-text"> </span>
|
||||
{{/if}}
|
||||
</span>
|
||||
<span class="full-label">{{label}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('views/admin/entity-manager/fields/icon-class', 'views/fields/base', function (Dep) {
|
||||
define('views/admin/entity-manager/fields/icon-class', 'views/fields/base', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -44,15 +44,24 @@ Espo.define('views/admin/entity-manager/fields/icon-class', 'views/fields/base',
|
||||
this.createView('dialog', 'views/admin/entity-manager/modals/select-icon', {}, function (view) {
|
||||
view.render();
|
||||
this.listenToOnce(view, 'select', function (value) {
|
||||
if (value === '') {
|
||||
value = null;
|
||||
}
|
||||
|
||||
this.model.set(this.name, value);
|
||||
|
||||
view.close();
|
||||
}, this);
|
||||
});
|
||||
},
|
||||
|
||||
fetch: function () {
|
||||
return {};
|
||||
}
|
||||
var data = {};
|
||||
|
||||
data[this.name] = this.model.get(this.name);
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,6 +46,8 @@ define('views/fields/array', ['views/fields/base', 'lib!Selectize'], function (D
|
||||
|
||||
validations: ['required', 'maxCount'],
|
||||
|
||||
addItemModalView: 'views/modals/array-field-add',
|
||||
|
||||
data: function () {
|
||||
var itemHtmlList = [];
|
||||
(this.selected || []).forEach(function (value) {
|
||||
@@ -70,24 +72,8 @@ define('views/fields/array', ['views/fields/base', 'lib!Selectize'], function (D
|
||||
this.removeValue(value);
|
||||
},
|
||||
'click [data-action="showAddModal"]': function () {
|
||||
var options = [];
|
||||
|
||||
this.params.options.forEach(function (item) {
|
||||
if (!~this.selected.indexOf(item)) {
|
||||
options.push(item);
|
||||
}
|
||||
}, this);
|
||||
this.createView('addModal', 'views/modals/array-field-add', {
|
||||
options: options,
|
||||
translatedOptions: this.translatedOptions
|
||||
}, function (view) {
|
||||
view.render();
|
||||
this.listenToOnce(view, 'add', function (item) {
|
||||
this.addValue(item);
|
||||
view.close();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
this.actionAddItem();
|
||||
},
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
@@ -590,5 +576,26 @@ define('views/fields/array', ['views/fields/base', 'lib!Selectize'], function (D
|
||||
getSearchType: function () {
|
||||
return this.getSearchParamsData().type || 'anyOf';
|
||||
},
|
||||
|
||||
actionAddItem: function () {
|
||||
var options = [];
|
||||
|
||||
this.params.options.forEach(function (item) {
|
||||
if (!~this.selected.indexOf(item)) {
|
||||
options.push(item);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.createView('addModal', this.addItemModalView, {
|
||||
options: options,
|
||||
translatedOptions: this.translatedOptions,
|
||||
}, function (view) {
|
||||
view.render();
|
||||
this.listenToOnce(view, 'add', function (item) {
|
||||
this.addValue(item);
|
||||
view.close();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ define('views/modals/array-field-add', 'views/modal', function (Dep) {
|
||||
data: function () {
|
||||
return {
|
||||
optionList: this.options.options,
|
||||
translatedOptions: this.options.translatedOptions
|
||||
translatedOptions: this.options.translatedOptions,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -53,16 +53,9 @@ define('views/modals/array-field-add', 'views/modal', function (Dep) {
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
|
||||
this.header = this.translate('Add Item');
|
||||
|
||||
this.buttonList = [
|
||||
{
|
||||
name: 'cancel',
|
||||
label: 'Cancel'
|
||||
}
|
||||
];
|
||||
|
||||
this.buttonList = [];
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
@@ -124,6 +124,8 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
|
||||
panelSoftLockedTypeList: ['default', 'acl', 'delimiter', 'dynamicLogic'],
|
||||
|
||||
confirmLeaveDisabled: false,
|
||||
|
||||
events: {
|
||||
'click .button-container .action': function (e) {
|
||||
Espo.Utils.handleAction(this, e);
|
||||
@@ -1085,11 +1087,21 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
|
||||
setIsChanged: function () {
|
||||
this.isChanged = true;
|
||||
|
||||
if (this.confirmLeaveDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setConfirmLeaveOut(true);
|
||||
},
|
||||
|
||||
setIsNotChanged: function () {
|
||||
this.isChanged = false;
|
||||
|
||||
if (this.confirmLeaveDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setConfirmLeaveOut(false);
|
||||
},
|
||||
|
||||
|
||||
@@ -40,5 +40,7 @@ define('views/record/edit-for-modal', 'views/record/edit', function (Dep) {
|
||||
|
||||
accessControlDisabled: true,
|
||||
|
||||
confirmLeaveDisabled: true,
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/settings/fields/group-tab-list', 'views/settings/fields/tab-list', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
noGroups: true,
|
||||
|
||||
noDelimiters: true,
|
||||
|
||||
});
|
||||
});
|
||||
@@ -30,17 +30,59 @@ define('views/settings/fields/tab-list', 'views/fields/array', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
addItemModalView: 'views/settings/modals/tab-list-field-add',
|
||||
|
||||
noGroups: false,
|
||||
|
||||
noDelimiters: false,
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
this.selected.forEach(function (item) {
|
||||
if (item && typeof item === 'object') {
|
||||
if (!item.id) {
|
||||
item.id = this.generateItemId();
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.events['click [data-action="editGroup"]'] = function (e) {
|
||||
var id = $(e.currentTarget).parent().data('value').toString();
|
||||
|
||||
this.editGroup(id);
|
||||
}.bind(this);
|
||||
},
|
||||
|
||||
generateItemId: function () {
|
||||
return Math.floor(Math.random() * 1000000 + 1).toString();
|
||||
},
|
||||
|
||||
setupOptions: function () {
|
||||
this.params.options = Object.keys(this.getMetadata().get('scopes'))
|
||||
.filter(
|
||||
function (scope) {
|
||||
if (this.getMetadata().get('scopes.' + scope + '.disabled')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.params.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) {
|
||||
if (this.getMetadata().get('scopes.' + scope + '.disabled')) return;
|
||||
return this.getMetadata().get('scopes.' + scope + '.tab');
|
||||
}, this).sort(function (v1, v2) {
|
||||
return this.translate(v1, 'scopeNamesPlural').localeCompare(this.translate(v2, 'scopeNamesPlural'));
|
||||
}.bind(this));
|
||||
if (!this.getAcl().checkScope(scope)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.params.options.push('_delimiter_');
|
||||
this.params.options.push('_delimiter-ext_');
|
||||
return this.getMetadata().get('scopes.' + scope + '.tab');
|
||||
},
|
||||
this
|
||||
).sort(
|
||||
function (v1, v2) {
|
||||
return this.translate(v1, 'scopeNamesPlural').localeCompare(this.translate(v2, 'scopeNamesPlural'));
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
if (!this.noDelimiters) {
|
||||
this.params.options.push('_delimiter_');
|
||||
this.params.options.push('_delimiter-ext_');
|
||||
}
|
||||
|
||||
this.translatedOptions = {};
|
||||
|
||||
@@ -52,5 +94,160 @@ define('views/settings/fields/tab-list', 'views/fields/array', function (Dep) {
|
||||
this.translatedOptions['_delimiter-ext_'] = '. . .';
|
||||
},
|
||||
|
||||
addValue: function (value) {
|
||||
if (value && typeof value === 'object') {
|
||||
if (!value.id) {
|
||||
value.id = this.generateItemId();
|
||||
}
|
||||
|
||||
var html = this.getItemHtml(value);
|
||||
|
||||
this.$list.append(html);
|
||||
|
||||
this.selected.push(value);
|
||||
|
||||
this.trigger('change');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Dep.prototype.addValue.call(this, value);
|
||||
},
|
||||
|
||||
removeValue: function (value) {
|
||||
var index = this.getGroupIndexById(value);
|
||||
|
||||
if (~index) {
|
||||
this.$list.children('[data-value="' + value + '"]').remove();
|
||||
|
||||
this.selected.splice(index, 1);
|
||||
this.trigger('change');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Dep.prototype.removeValue.call(this, value);
|
||||
},
|
||||
|
||||
getItemHtml: function (value) {
|
||||
if (value && typeof value === 'object') {
|
||||
return this.getGroupItemHtml(value);
|
||||
}
|
||||
|
||||
return Dep.prototype.getItemHtml.call(this, value);
|
||||
},
|
||||
|
||||
getGroupItemHtml: function (item) {
|
||||
var label = this.escapeValue(item.text || '');
|
||||
|
||||
var html = '<div class="list-group-item" data-value="' + item.id + '" style="cursor: default;">' +
|
||||
'<a href="javascript:" class="" data-value="' + item.id + '" ' +
|
||||
'data-action="editGroup" style="margin-right: 7px;">' +
|
||||
'<span class="fas fa-pencil-alt fa-sm"></span>' +
|
||||
'</a>' +
|
||||
label +
|
||||
' ' +
|
||||
'<a href="javascript:" class="pull-right" data-value="' + item.id + '" data-action="removeValue">' +
|
||||
'<span class="fas fa-times"></span>' +
|
||||
'</a>' +
|
||||
'</div>';
|
||||
|
||||
return html;
|
||||
},
|
||||
|
||||
fetchFromDom: function () {
|
||||
var selected = [];
|
||||
|
||||
this.$el.find('.list-group .list-group-item').each(function (i, el) {
|
||||
var value = $(el).data('value').toString();
|
||||
|
||||
var groupItem = this.getGroupValueById(value);
|
||||
|
||||
if (groupItem) {
|
||||
selected.push(groupItem);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
selected.push(value);
|
||||
}.bind(this));
|
||||
|
||||
this.selected = selected;
|
||||
},
|
||||
|
||||
getGroupIndexById: function (id) {
|
||||
for (var i = 0; i < this.selected.length; i++) {
|
||||
var item = this.selected[i];
|
||||
|
||||
if (item && typeof item === 'object') {
|
||||
if (item.id === id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
},
|
||||
|
||||
getGroupValueById: function (id) {
|
||||
for (var item of this.selected) {
|
||||
if (item && typeof item === 'object') {
|
||||
if (item.id === id) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
editGroup: function (id) {
|
||||
var item = Espo.Utils.cloneDeep(
|
||||
this.getGroupValueById(id) || {}
|
||||
);
|
||||
|
||||
var index = this.getGroupIndexById(id);
|
||||
|
||||
var tabList = Espo.Utils.cloneDeep(this.selected);
|
||||
|
||||
this.createView('dialog', 'views/settings/modals/edit-tab-group', {
|
||||
itemData: item,
|
||||
}, function (view) {
|
||||
view.render();
|
||||
|
||||
this.listenToOnce(view, 'apply', function (itemData) {
|
||||
for (var a in itemData) {
|
||||
tabList[index][a] = itemData[a];
|
||||
}
|
||||
|
||||
this.model.set(this.name, tabList);
|
||||
|
||||
view.close();
|
||||
}, this);
|
||||
});
|
||||
},
|
||||
|
||||
actionAddItem: function () {
|
||||
var options = [];
|
||||
|
||||
this.params.options.forEach(function (item) {
|
||||
if (!~this.selected.indexOf(item)) {
|
||||
options.push(item);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.createView('addModal', this.addItemModalView, {
|
||||
options: options,
|
||||
translatedOptions: this.translatedOptions,
|
||||
noGroups: this.noGroups,
|
||||
}, function (view) {
|
||||
view.render();
|
||||
this.listenToOnce(view, 'add', function (item) {
|
||||
this.addValue(item);
|
||||
view.close();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/settings/modals/edit-tab-group', ['views/modal', 'model'], function (Dep, Model) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
templateContent: '<div class="record">{{{record}}}</div>',
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
this.headerHtml = this.translate('Group Tab', 'labels', 'Settings');
|
||||
|
||||
this.buttonList.push({
|
||||
name: 'apply',
|
||||
label: 'Apply',
|
||||
style: 'danger',
|
||||
});
|
||||
|
||||
this.buttonList.push({
|
||||
name: 'cancel',
|
||||
label: 'Cancel',
|
||||
});
|
||||
|
||||
var detailLayout = [
|
||||
{
|
||||
rows: [
|
||||
[
|
||||
{
|
||||
name: 'text',
|
||||
labelText: this.translate('label', 'fields', 'Admin'),
|
||||
},
|
||||
{
|
||||
name: 'iconClass',
|
||||
labelText: this.translate('iconClass', 'fields', 'EntityManager'),
|
||||
},
|
||||
{
|
||||
name: 'color',
|
||||
labelText: this.translate('color', 'fields', 'EntityManager'),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'itemList',
|
||||
labelText: this.translate('tabList', 'fields', 'Settings'),
|
||||
},
|
||||
false
|
||||
]
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
var model = this.model = new Model();
|
||||
|
||||
model.name = 'GroupTab';
|
||||
|
||||
model.set(this.options.itemData);
|
||||
|
||||
model.setDefs({
|
||||
fields: {
|
||||
text: {
|
||||
type: 'varchar',
|
||||
},
|
||||
iconClass: {
|
||||
type: 'base',
|
||||
view: 'views/admin/entity-manager/fields/icon-class',
|
||||
},
|
||||
color: {
|
||||
type: 'base',
|
||||
view: 'views/fields/colorpicker',
|
||||
},
|
||||
itemList: {
|
||||
type: 'array',
|
||||
view: 'views/settings/fields/group-tab-list',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.createView('record', 'views/record/edit-for-modal', {
|
||||
detailLayout: detailLayout,
|
||||
model: model,
|
||||
el: this.getSelector() + ' .record',
|
||||
});
|
||||
},
|
||||
|
||||
actionApply: function () {
|
||||
var recordView = this.getView('record');
|
||||
|
||||
if (recordView.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var data = recordView.fetch();
|
||||
|
||||
this.trigger('apply', data);
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/settings/modals/tab-list-field-add', 'views/modals/array-field-add', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
if (!this.options.noGroups) {
|
||||
this.buttonList.push({
|
||||
name: 'addGroup',
|
||||
html: this.translate('Group Tab', 'labels', 'Settings'),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
actionAddGroup: function () {
|
||||
this.trigger('add', {
|
||||
type: 'group',
|
||||
text: this.translate('Group Tab', 'labels', 'Settings'),
|
||||
iconClass: null,
|
||||
color: null,
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
+390
-65
@@ -91,6 +91,157 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
e.stopPropagation();
|
||||
this.showMoreTabs();
|
||||
},
|
||||
'click .not-in-more > .nav-link-group': function (e) {
|
||||
this.handleGroupDropdownClick(e);
|
||||
},
|
||||
'click .in-more .nav-link-group': function (e) {
|
||||
this.handleGroupDropdownClick(e);
|
||||
},
|
||||
},
|
||||
|
||||
handleGroupDropdownClick: function (e) {
|
||||
var $target = $(e.currentTarget).parent();
|
||||
|
||||
if ($target.parent().hasClass('more-dropdown-menu')) {
|
||||
e.stopPropagation();
|
||||
|
||||
if ($target.hasClass('open')) {
|
||||
$target.removeClass('open');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleGroupDropdownInMoreOpen($target);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($target.hasClass('open')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleGroupDropdownOpen($target);
|
||||
},
|
||||
|
||||
handleGroupMenuPosition: function ($menu, $target) {
|
||||
if (this.navbarAdjustmentHandler && this.navbarAdjustmentHandler.handleGroupMenuPosition()) {
|
||||
this.handleGroupMenuPosition($menu, $target);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var rectItem = $target.get(0).getBoundingClientRect();
|
||||
|
||||
var windowHeight = window.innerHeight;
|
||||
|
||||
var isVertical = this.getThemeManager().getParam('navbarIsVertical');
|
||||
|
||||
if (
|
||||
!isVertical &&
|
||||
!$target.parent().hasClass('more-dropdown-menu')
|
||||
) {
|
||||
var maxHeight = windowHeight - rectItem.bottom;
|
||||
|
||||
this.handleGroupMenuScrolling($menu, $target, maxHeight);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var itemCount = $menu.children().length;
|
||||
|
||||
if (isVertical) {
|
||||
var tabHeight = this.$tabs.find('> .tab').height();
|
||||
} else {
|
||||
var tabHeight = this.$tabs.find('.tab-group > ul > li:visible').height();
|
||||
}
|
||||
|
||||
var menuHeight = tabHeight * itemCount;
|
||||
|
||||
var top = rectItem.top - 1;
|
||||
|
||||
if (top + menuHeight > windowHeight) {
|
||||
top = windowHeight - menuHeight - 2;
|
||||
|
||||
if (top < 0) {
|
||||
top = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$menu.css({
|
||||
top: top + 'px',
|
||||
});
|
||||
|
||||
var maxHeight = windowHeight - top;
|
||||
|
||||
this.handleGroupMenuScrolling($menu, $target, maxHeight);
|
||||
},
|
||||
|
||||
handleGroupMenuScrolling: function ($menu, $target, maxHeight) {
|
||||
$menu.css({
|
||||
maxHeight: maxHeight + 'px',
|
||||
});
|
||||
|
||||
var $window = $(window);
|
||||
|
||||
$window.off('scroll.navbar-tab-group');
|
||||
|
||||
$window.on('scroll.navbar-tab-group', function () {
|
||||
if (!$menu.get(0) || !$target.get(0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$target.hasClass('open')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$menu.scrollTop($window.scrollTop());
|
||||
});
|
||||
},
|
||||
|
||||
handleGroupDropdownOpen: function ($target) {
|
||||
var $menu = $target.find('.dropdown-menu');
|
||||
|
||||
this.handleGroupMenuPosition($menu, $target);
|
||||
|
||||
setTimeout(function () {
|
||||
this.adjustBodyMinHeight();
|
||||
}.bind(this), 50);
|
||||
|
||||
$target.off('hidden.bs.dropdown');
|
||||
|
||||
$target.on('hidden.bs.dropdown', function () {
|
||||
this.adjustBodyMinHeight();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
handleGroupDropdownInMoreOpen: function ($target) {
|
||||
this.$el.find('.tab-group.tab.dropdown').removeClass('open');
|
||||
|
||||
var $parentDropdown = this.$el.find('.more-dropdown-menu');
|
||||
|
||||
$target.addClass('open');
|
||||
|
||||
var $menu = $target.find('.dropdown-menu');
|
||||
|
||||
var rectDropdown = $parentDropdown.get(0).getBoundingClientRect();
|
||||
|
||||
var left = rectDropdown.right;
|
||||
|
||||
$menu.css({
|
||||
left: left + 'px',
|
||||
});
|
||||
|
||||
this.handleGroupMenuPosition($menu, $target);
|
||||
|
||||
this.adjustBodyMinHeight();
|
||||
|
||||
if (!this.getThemeManager().getParam('isVertical')) {
|
||||
if (left + $menu.width() > window.innerWidth) {
|
||||
$menu.css({
|
||||
left: rectDropdown.left - $menu.width() - 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isCollapsableVisible: function () {
|
||||
@@ -183,12 +334,16 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
},
|
||||
|
||||
getTabList: function () {
|
||||
var tabList = this.getPreferences().get('useCustomTabList') ? this.getPreferences().get('tabList') : this.getConfig().get('tabList');
|
||||
tabList = Espo.Utils.clone(tabList || []);
|
||||
var tabList = this.getPreferences().get('useCustomTabList') ?
|
||||
this.getPreferences().get('tabList') :
|
||||
this.getConfig().get('tabList');
|
||||
|
||||
tabList = Espo.Utils.cloneDeep(tabList || []);
|
||||
|
||||
if (this.getThemeManager().getParam('navbarIsVertical')) {
|
||||
tabList.unshift('Home');
|
||||
}
|
||||
|
||||
return tabList;
|
||||
},
|
||||
|
||||
@@ -209,23 +364,33 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
|
||||
var scopes = this.getMetadata().get('scopes') || {};
|
||||
|
||||
this.tabList = tabList.filter(function (scope) {
|
||||
if (~['Home', '_delimiter_', '_delimiter-ext_'].indexOf(scope)) return true;
|
||||
if (!scopes[scope]) return false;
|
||||
this.tabList = tabList.filter(
|
||||
function (item) {
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var defs = scopes[scope] || {};
|
||||
if (typeof item === 'object') {
|
||||
item.itemList = item.itemList || [];
|
||||
|
||||
if (defs.disabled) return;
|
||||
item.itemList = item.itemList.filter(
|
||||
function (item) {
|
||||
return this.filterTabItem(item);
|
||||
},
|
||||
this
|
||||
);
|
||||
|
||||
if (defs.acl) {
|
||||
return this.getAcl().check(scope);
|
||||
}
|
||||
if (defs.tabAclPermission) {
|
||||
var level = this.getAcl().get(defs.tabAclPermission);
|
||||
return level && level !== 'no';
|
||||
}
|
||||
return true;
|
||||
}, this);
|
||||
if (!item.itemList.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.filterTabItem(item);
|
||||
},
|
||||
this
|
||||
);
|
||||
|
||||
this.quickCreateList = this.getQuickCreateList().filter(function (scope) {
|
||||
if (!scopes[scope]) return false;
|
||||
@@ -247,9 +412,39 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
this.once('remove', function () {
|
||||
$(window).off('resize.navbar');
|
||||
$(window).off('scroll.navbar');
|
||||
$(window).off('scroll.navbar-tab-group');
|
||||
});
|
||||
},
|
||||
|
||||
filterTabItem: function (scope) {
|
||||
if (~['Home', '_delimiter_', '_delimiter-ext_'].indexOf(scope)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var scopes = this.getMetadata().get('scopes') || {};
|
||||
|
||||
if (!scopes[scope]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var defs = scopes[scope] || {};
|
||||
|
||||
if (defs.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (defs.acl) {
|
||||
return this.getAcl().check(scope);
|
||||
}
|
||||
if (defs.tabAclPermission) {
|
||||
var level = this.getAcl().get(defs.tabAclPermission);
|
||||
|
||||
return level && level !== 'no';
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
setupGlobalSearch: function () {
|
||||
this.globalSearchAvailable = false;
|
||||
(this.getConfig().get('globalSearchEntityList') || []).forEach(function (scope) {
|
||||
@@ -491,23 +686,73 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
|
||||
minHeight = Math.max(minHeight, moreHeight);
|
||||
|
||||
var tabHeight = this.$tabs.find('> .tab').height();
|
||||
|
||||
this.tabList.forEach(function (item, i) {
|
||||
if (typeof item !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
var $li = this.$el.find('li.tab[data-name="group-'+i+'"]');
|
||||
|
||||
if (!$li.hasClass('open')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tabCount = (item.itemList || []).length;
|
||||
|
||||
var menuHeight = tabHeight * tabCount;
|
||||
|
||||
if (menuHeight > minHeight) {
|
||||
minHeight = menuHeight;
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.$body.css('minHeight', minHeight + 'px');
|
||||
},
|
||||
|
||||
adjustBodyMinHeightHorizontal: function () {
|
||||
var height = this.getNavbarHeight();
|
||||
var minHeight = this.getNavbarHeight();
|
||||
|
||||
this.$more.find('> li').each(function (i, el) {
|
||||
var $el = $(el);
|
||||
|
||||
if (!this.isMoreTabsShown) {
|
||||
if ($el.hasClass('after-show-more')) return;
|
||||
if ($el.hasClass('after-show-more')) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ($el.hasClass('show-more')) return;
|
||||
if ($el.hasClass('show-more')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
height += $el.height();
|
||||
|
||||
minHeight += $el.height();
|
||||
}.bind(this));
|
||||
|
||||
this.$body.css('minHeight', height + 'px');
|
||||
var tabHeight = this.$tabs.find('.tab-group > ul > li:visible').height();
|
||||
|
||||
this.tabList.forEach(function (item, i) {
|
||||
if (typeof item !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
var $li = this.$el.find('li.tab[data-name="group-'+i+'"]');
|
||||
|
||||
if (!$li.hasClass('open')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tabCount = (item.itemList || []).length;
|
||||
|
||||
var menuHeight = tabHeight * tabCount;
|
||||
|
||||
if (menuHeight > minHeight) {
|
||||
minHeight = menuHeight;
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.$body.css('minHeight', minHeight + 'px');
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
@@ -551,6 +796,9 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
if (handlerClassName) {
|
||||
require(handlerClassName, function (Handler) {
|
||||
var handler = new Handler(this);
|
||||
|
||||
this.navbarAdjustmentHandler = handler;
|
||||
|
||||
handler.process();
|
||||
}.bind(this));
|
||||
}
|
||||
@@ -606,6 +854,7 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
|
||||
setupTabDefsList: function () {
|
||||
var tabDefsList = [];
|
||||
|
||||
var moreIsMet = false;
|
||||
var isHidden = false;
|
||||
|
||||
@@ -614,16 +863,32 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
this.getPreferences().get('tabColorsDisabled') ||
|
||||
this.getConfig().get('scopeColorsDisabled') ||
|
||||
this.getConfig().get('tabColorsDisabled');
|
||||
|
||||
var tabIconsDisabled = this.getConfig().get('tabIconsDisabled');
|
||||
|
||||
var params = {
|
||||
colorsDisabled: colorsDisabled,
|
||||
tabIconsDisabled: tabIconsDisabled,
|
||||
};
|
||||
|
||||
var vars = {
|
||||
moreIsMet: false,
|
||||
isHidden: false,
|
||||
};
|
||||
|
||||
this.tabList.forEach(function (tab, i) {
|
||||
if (tab === '_delimiter_' || tab === '_delimiter-ext_') {
|
||||
if (!moreIsMet) {
|
||||
moreIsMet = true;
|
||||
if (!vars.moreIsMet) {
|
||||
vars.moreIsMet = true;
|
||||
|
||||
return;
|
||||
} else {
|
||||
if (i == this.tabList.length - 1) return;
|
||||
isHidden = true;
|
||||
if (i == this.tabList.length - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
vars.isHidden = true;
|
||||
|
||||
tabDefsList.push({
|
||||
name: 'show-more',
|
||||
link: 'javascript:',
|
||||
@@ -631,53 +896,104 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
className: 'show-more',
|
||||
html: '<span class="fas fa-ellipsis-h more-icon"></span>',
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var label;
|
||||
var link;
|
||||
|
||||
if (tab == 'Home') {
|
||||
label = this.getLanguage().translate(tab);
|
||||
link = '#';
|
||||
} else {
|
||||
label = this.getLanguage().translate(tab, 'scopeNamesPlural');
|
||||
link = '#' + tab;
|
||||
}
|
||||
|
||||
var color = null;
|
||||
if (!colorsDisabled) {
|
||||
var color = this.getMetadata().get(['clientDefs', tab, 'color']);
|
||||
}
|
||||
|
||||
var shortLabel = label.substr(0, 2);
|
||||
|
||||
var iconClass = null;
|
||||
if (!tabIconsDisabled) {
|
||||
iconClass = this.getMetadata().get(['clientDefs', tab, 'iconClass'])
|
||||
}
|
||||
|
||||
var o = {
|
||||
link: link,
|
||||
label: label,
|
||||
shortLabel: shortLabel,
|
||||
name: tab,
|
||||
isInMore: moreIsMet,
|
||||
color: color,
|
||||
iconClass: iconClass,
|
||||
isAfterShowMore: isHidden,
|
||||
aClassName: 'nav-link',
|
||||
};
|
||||
if (isHidden) o.className = 'after-show-more';
|
||||
if (color && !iconClass) {
|
||||
o.colorIconClass = 'color-icon fas fa-square-full';
|
||||
}
|
||||
tabDefsList.push(o);
|
||||
tabDefsList.push(
|
||||
this.prepareTabItemDefs(params, tab, i, vars)
|
||||
);
|
||||
}, this);
|
||||
|
||||
this.tabDefsList = tabDefsList;
|
||||
},
|
||||
|
||||
prepareTabItemDefs: function (params, tab, i, vars) {
|
||||
var label;
|
||||
var link;
|
||||
|
||||
var iconClass = null;
|
||||
|
||||
var color = null;
|
||||
|
||||
var isGroup = false;
|
||||
|
||||
var name = tab;
|
||||
|
||||
var aClassName = 'nav-link';
|
||||
|
||||
if (tab == 'Home') {
|
||||
label = this.getLanguage().translate(tab);
|
||||
link = '#';
|
||||
}
|
||||
else if (typeof tab === 'object') {
|
||||
isGroup = true;
|
||||
|
||||
label = tab.text;
|
||||
color = tab.color;
|
||||
iconClass = tab.iconClass;
|
||||
|
||||
name = 'group-' + i;
|
||||
|
||||
link = 'javascript:';
|
||||
|
||||
aClassName = 'nav-link-group';
|
||||
|
||||
if (label.indexOf('label@') === 0) {
|
||||
label = this.translate(label.substr(6), 'tabs');
|
||||
}
|
||||
}
|
||||
else {
|
||||
label = this.getLanguage().translate(tab, 'scopeNamesPlural');
|
||||
link = '#' + tab;
|
||||
}
|
||||
|
||||
label = label || '';
|
||||
|
||||
var shortLabel = label.substr(0, 2);
|
||||
|
||||
if (!params.colorsDisabled && !isGroup) {
|
||||
color = this.getMetadata().get(['clientDefs', tab, 'color']);
|
||||
}
|
||||
|
||||
if (!params.tabIconsDisabled && !isGroup) {
|
||||
iconClass = this.getMetadata().get(['clientDefs', tab, 'iconClass'])
|
||||
}
|
||||
|
||||
var o = {
|
||||
link: link,
|
||||
label: label,
|
||||
shortLabel: shortLabel,
|
||||
name: name,
|
||||
isInMore: vars.moreIsMet,
|
||||
color: color,
|
||||
iconClass: iconClass,
|
||||
isAfterShowMore: vars.isHidden,
|
||||
aClassName: aClassName,
|
||||
isGroup: isGroup,
|
||||
};
|
||||
|
||||
if (isGroup) {
|
||||
o.itemList = tab.itemList.map(
|
||||
function (tab, i) {
|
||||
return this.prepareTabItemDefs(params, tab, i, vars);
|
||||
},
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
if (vars.isHidden) {
|
||||
o.className = 'after-show-more';
|
||||
}
|
||||
|
||||
if (color && !iconClass) {
|
||||
o.colorIconClass = 'color-icon fas fa-square-full';
|
||||
}
|
||||
|
||||
return o;
|
||||
},
|
||||
|
||||
getMenuDataList: function () {
|
||||
var avatarHtml = this.getHelper().getAvatarHtml(this.getUser().id, 'small', 16, 'avatar-link');
|
||||
if (avatarHtml) avatarHtml += ' ';
|
||||
@@ -765,15 +1081,24 @@ define('views/site/navbar', 'view', function (Dep) {
|
||||
},
|
||||
|
||||
showMoreTabs: function () {
|
||||
this.$el.find('.tab-group.tab.dropdown').removeClass('open');
|
||||
|
||||
this.isMoreTabsShown = true;
|
||||
|
||||
this.$more.addClass('more-expanded');
|
||||
|
||||
this.adjustBodyMinHeight();
|
||||
|
||||
this.trigger('show-more-tabs');
|
||||
},
|
||||
|
||||
hideMoreTabs: function () {
|
||||
if (!this.isMoreTabsShown) return;
|
||||
if (!this.isMoreTabsShown) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$more.removeClass('more-expanded');
|
||||
|
||||
this.adjustBodyMinHeight();
|
||||
|
||||
this.isMoreTabsShown = false;
|
||||
|
||||
@@ -46,17 +46,40 @@
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.nav > li.more > .dropdown-menu {
|
||||
.nav > li.more > .dropdown-menu > li > ul.dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.nav > li.more > .dropdown-menu,
|
||||
.nav > li.more > .dropdown-menu > li.tab-group > ul.dropdown-menu,
|
||||
.nav > li.tab-group > .dropdown-menu {
|
||||
top: 0;
|
||||
left: @navbar-width;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
position: fixed;
|
||||
border-left-width: 0;
|
||||
border-top-width: 0;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.nav > li.more > .dropdown-menu,
|
||||
.nav > li.tab-group > .dropdown-menu {
|
||||
border-left-width: 0;
|
||||
}
|
||||
|
||||
.nav > li.more > .dropdown-menu {
|
||||
border-top-width: 0;
|
||||
}
|
||||
|
||||
.nav li.tab-group {
|
||||
span.full-label {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.group-caret {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
ul.tabs {
|
||||
width: @navbar-width;
|
||||
margin-left: 0;
|
||||
@@ -369,7 +392,8 @@ body {
|
||||
}
|
||||
|
||||
#navbar {
|
||||
.nav > li.more > ul.dropdown-menu {
|
||||
.nav > li.more > ul.dropdown-menu,
|
||||
.nav > li.tab-group > .dropdown-menu {
|
||||
left: @navbar-minimized-width;
|
||||
}
|
||||
|
||||
@@ -432,6 +456,10 @@ body {
|
||||
left: -1px;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
> li.tab-group .group-caret {
|
||||
right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-right {
|
||||
|
||||
@@ -36,6 +36,16 @@
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
ul.tabs {
|
||||
li > a > .group-caret {
|
||||
position: absolute;
|
||||
top: 13px;
|
||||
right: 13px;
|
||||
font-size: 12px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: @screen-sm-min) {
|
||||
.tabs > .more {
|
||||
li.show-more a {
|
||||
@@ -131,6 +141,39 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> li > a > span.full-label,
|
||||
li > a > span.full-label {
|
||||
display: inline-block;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc(100%);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
li > a > .group-caret {
|
||||
-webkit-transform: rotate(90deg);
|
||||
-moz-transform: rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
-o-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
li > a {
|
||||
height: @navbar-height-xsmall;
|
||||
}
|
||||
|
||||
li.tab-group {
|
||||
background-color: @navbar-inverse-bg;
|
||||
|
||||
> a > .full-label {
|
||||
padding-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
li.tab-group.open > a {
|
||||
background-color: @navbar-inverse-link-active-bg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,11 +49,15 @@
|
||||
display: inline;
|
||||
}
|
||||
|
||||
> li.more {
|
||||
> ul {
|
||||
> li.more,
|
||||
> li.tab-group {
|
||||
> ul,
|
||||
> ul > li > ul {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
> ul > li > ul > li > a,
|
||||
> ul > li > a {
|
||||
padding-top: 9px;
|
||||
padding-bottom: 9px;
|
||||
@@ -75,6 +79,10 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
li.tab-group .group-caret {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-right {
|
||||
@@ -175,6 +183,36 @@
|
||||
border-color: transparent;
|
||||
padding-left: 15px - @navbar-color-border-width;
|
||||
}
|
||||
|
||||
.nav > li.more > .dropdown-menu > li.tab-group > ul.dropdown-menu,
|
||||
.nav > li.tab-group > .dropdown-menu {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.nav > li.more > .dropdown-menu > li.tab-group > ul.dropdown-menu {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.nav li.tab-group {
|
||||
span.full-label {
|
||||
padding-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
ul.nav > li.tab-group > a {
|
||||
> span.full-label {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
> span.group-caret {
|
||||
top: 17px;
|
||||
-webkit-transform: rotate(90deg);
|
||||
-moz-transform: rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
-o-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user