feat: RBAC + SAML support

This commit is contained in:
Markos Gogoulos
2025-04-05 12:44:21 +03:00
committed by GitHub
parent 8fecccce1c
commit 05414f66c7
158 changed files with 6423 additions and 106 deletions

951
static/jazzmin/css/main.css Normal file
View File

@@ -0,0 +1,951 @@
/** Django-related improvements to AdminLTE UI **/
div.inline-related {
padding: 10px;
}
.form-row {
padding: 5px;
}
.help-block ul {
margin: 10px 0 0 15px;
padding: 0;
}
/** Fix bug of adminLTE, since django is using th headers in middle of table **/
.card-body.p-0 .table thead > tr > th:first-of-type,
.card-body.p-0 .table thead > tr > td:first-of-type,
.card-body.p-0 .table tfoot > tr > th:first-of-type,
.card-body.p-0 .table tfoot > tr > td:first-of-type,
.card-body.p-0 .table tbody > tr > th:first-of-type,
.card-body.p-0 .table tbody > tr > td:first-of-type {
padding-left: 0.75rem;
}
.card-body.p-0 .table thead > tr > th:last-of-type,
.card-body.p-0 .table thead > tr > td:last-of-type,
.card-body.p-0 .table tfoot > tr > th:last-of-type,
.card-body.p-0 .table tfoot > tr > td:last-of-type,
.card-body.p-0 .table tbody > tr > th:last-of-type,
.card-body.p-0 .table tbody > tr > td:last-of-type {
padding-right: 0.75rem;
}
.card-body.p-0 .table thead > tr > th:first-child,
.card-body.p-0 .table thead > tr > td:first-child,
.card-body.p-0 .table tfoot > tr > th:first-child,
.card-body.p-0 .table tfoot > tr > td:first-child,
.card-body.p-0 .table tbody > tr > th:first-child,
.card-body.p-0 .table tbody > tr > td:first-child {
padding-left: 1.5rem;
}
.card-body.p-0 .table thead > tr > th:last-child,
.card-body.p-0 .table thead > tr > td:last-child,
.card-body.p-0 .table tfoot > tr > th:last-child,
.card-body.p-0 .table tfoot > tr > td:last-child,
.card-body.p-0 .table tbody > tr > th:last-child,
.card-body.p-0 .table tbody > tr > td:last-child {
padding-right: 1.5rem;
}
[class*=sidebar-dark-] .nav-header {
margin-top: 1rem;
}
.nav-sidebar .nav-header {
font-size: 1.2rem !important
}
/* Table styles */
.table tr.form-row {
display: table-row;
}
.table td.action-checkbox {
width: 45px;
}
.table thead th {
color: #64748b;
border-bottom: 0;
}
.empty-form {
display: none !important;
}
.inline-related .tabular {
background-color: white;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
td.djn-td,
th.djn-th {
padding: 10px;
}
td.delete input {
margin: 10px;
}
tr.djn-tr>.original {
padding-left: 20px;
}
.hidden {
display: none;
}
/* Checkbox selection table header */
.djn-checkbox-select-all {
padding-right: 0 !important;
width: 0;
}
.object-tools {
padding: 0;
}
.object-tools li {
list-style: none;
margin: 0;
padding: 0;
}
.object-tools .historylink {
background-color: #3c8dbc;
width: 100%;
display: block;
padding: 5px;
text-align: center;
color: white;
}
.jazzmin-avatar {
font-size: 20px;
}
.related-widget-wrapper-link {
padding: 7px;
}
.related-widget-wrapper select {
width: initial;
/* Setting a width will make the *-related btns overflow */
height: auto;
padding: .375rem .75rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: .25rem;
box-shadow: inset 0 0 0 transparent;
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
.tab-pane {
overflow-x: auto;
}
table.dataTable thead .sorting::after,
table.dataTable thead .sorting_asc::after,
table.dataTable thead .sorting_desc::after,
table.dataTable thead .sorting_asc_disabled::after,
table.dataTable thead .sorting_desc_disabled::after {
right: 0.5em;
content: "\2193";
}
.select2-container {
min-width: 200px;
}
.select2-container .select2-selection--single {
border: 1px solid #ced4da !important;
min-height: 38px;
/* Center text inside */
display: flex !important;
align-items: center;
}
.select2-container--default .select2-selection--single {
border: 1px solid #ced4da;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
right: 5px !important;
top: unset !important;
}
.select2-results__option {
color: black;
}
.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] {
background-color: #0074f0 !important;
color: white !important;
}
.select2-container--default .select2-results__option--selected {
background-color: #ddd !important;
}
#changelist-search .form-group {
margin-bottom: .5em;
margin-right: .5em;
}
.table tbody tr th {
padding-left: .75rem;
}
.user-profile {
font-size: 2.4em;
}
.date-hierarchy {
margin-right: 8px;
display: block;
}
/* APP.CSS */
.form-group div .vTextField,
.form-group div .vLargeTextField,
.form-group div .vURLField,
.form-group div .vBigIntegerField,
.form-group div input[type="text"]
{
display: block;
width: 100%;
}
.vTextField,
.vLargeTextField,
.vURLField,
.vIntegerField,
.vBigIntegerField,
.vForeignKeyRawIdAdminField,
.vDateField,
.vTimeField,
input[type="number"],
input[type="text"]
{
height: calc(2.25rem + 2px);
padding: .375rem .75rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #495057;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: .25rem;
box-shadow: inset 0 0 0 transparent;
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
.vDateField,
.vTimeField {
margin-bottom: 5px;
display: inline-block;
}
.vLargeTextField {
height: auto;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
border: 1px solid #ccc;
}
.date-icon:before,
.clock-icon:before {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome !important;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
content: "\f073";
}
.clock-icon:before {
content: "\f017";
}
/* CALENDARS & CLOCKS */
.calendarbox,
.clockbox {
margin: 5px auto;
font-size: 12px;
width: 19em;
text-align: center;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
overflow: hidden;
position: relative;
}
.clockbox {
width: auto;
}
.calendar {
margin: 0;
padding: 0;
}
.calendar table {
margin: 0;
padding: 0;
border-collapse: collapse;
background: white;
width: 100%;
}
.calendar caption,
.calendarbox h2,
.clockbox h2 {
margin: 0;
text-align: center;
border-top: none;
background: #f5dd5d;
font-weight: 700;
font-size: 12px;
color: #333;
}
.clockbox h2 {
font-size: 16px;
padding: 5px;
}
.calendar th {
padding: 8px 5px;
background: #f8f8f8;
border-bottom: 1px solid #ddd;
font-weight: 400;
font-size: 12px;
text-align: center;
color: #666;
}
.calendar td {
font-weight: 400;
font-size: 12px;
text-align: center;
padding: 0;
border-top: 1px solid #eee;
border-bottom: none;
}
.calendar td.selected a {
background: #3C8DBC;
color: #fff !important;
}
.calendar td.nonday {
background: #f8f8f8;
}
.calendar td.today a {
font-weight: 700;
}
.calendar td a,
.timelist a {
display: block;
font-weight: 400;
padding: 6px;
text-decoration: none;
color: #444;
}
.calendar td a:focus,
.timelist a:focus,
.calendar td a:hover,
.timelist a:hover {
background: #3C8DBC;
color: white;
}
.calendar td a:active,
.timelist a:active {
background: #3C8DBC;
color: white;
}
.calendarnav {
font-size: 10px;
text-align: center;
color: #ccc;
margin: 0;
padding: 1px 3px;
}
.calendarnav a:link,
#calendarnav a:visited,
#calendarnav a:focus,
#calendarnav a:hover {
color: #999;
}
.calendar-shortcuts {
background: white;
font-size: 11px;
line-height: 11px;
border-top: 1px solid #eee;
padding: 8px 0;
color: #ccc;
}
.calendarbox .calendarnav-previous,
.calendarbox .calendarnav-next {
display: block;
position: absolute;
top: 8px;
width: 15px;
height: 15px;
text-indent: -9999px;
padding: 0;
}
.calendarnav-previous {
left: 10px;
background: url(../img/calendar-icons.svg) 0 0 no-repeat;
}
.calendarbox .calendarnav-previous:focus,
.calendarbox .calendarnav-previous:hover {
background-position: 0 -15px;
}
.calendarnav-next {
right: 10px;
background: url(../img/calendar-icons.svg) 0 -30px no-repeat;
}
.calendarbox .calendarnav-next:focus,
.calendarbox .calendarnav-next:hover {
background-position: 0 -45px;
}
.calendar-cancel {
margin: 0;
padding: 4px 0;
font-size: 12px;
background: #eee;
border-top: 1px solid #ddd;
color: #333;
}
.calendar-cancel:focus,
.calendar-cancel:hover {
background: #ddd;
}
.calendar-cancel a {
color: black;
display: block;
}
/* Selectors - This needs some work TODO */
.selector {
width: 100%;
float: left;
}
.selector select {
width: 100%;
height: 15em;
}
.selector-available,
.selector-chosen {
float: left;
width: 48%;
text-align: center;
margin-bottom: 5px;
}
.selector-available h2,
.selector-chosen h2 {
border: 1px solid #ccc;
font-size: 16px;
padding: 5px;
}
.selector-chosen h2 {
background: #007bff;
color: #fff;
}
.selector .selector-available h2 {
background: #f8f8f8;
color: #666;
}
.selector .selector-filter {
background: white;
border: 1px solid #ccc;
padding: 8px;
color: #999;
font-size: 10px;
margin: 0;
text-align: left;
}
.selector-filter input {
height: 24px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
border: 1px solid #ccc;
margin-left: 0 !important;
}
.selector .selector-filter label,
.inline-group .aligned .selector .selector-filter label {
float: left;
margin: 0;
width: 18px;
height: 18px;
padding: 0;
overflow: hidden;
line-height: 1;
}
select#id_rbac_groups_from,
select#id_rbac_groups_to,
select#id_contributors_field_to,
select#id_contributors_field_from,
select#id_members_field_to,
select#id_members_field_from,
select#id_managers_field_to,
select#id_managers_field_from,
select#id_categories_to,
select#id_categories_from {
height: 285px !important;
}
/* Might need to import more rules from:
* https://github.com/django/django/blob/master/django/contrib/admin/static/admin/css/responsive.css
*/
.inline-group {
overflow: auto;
}
.selector .selector-available input {
width: 100%;
margin-left: 8px;
}
.selector ul.selector-chooser {
float: left;
width: 4%;
background-color: #eee;
border-radius: 10px;
margin: 10em 0 0;
padding: 0;
}
.selector-chooser li {
margin: 0;
padding: 3px;
list-style-type: none;
}
.selector select {
padding: 0 10px;
margin: 0 0 10px;
/*border-radius: 0 0 4px 4px;*/
;
}
.selector-add,
.selector-remove {
height: 16px;
display: block;
text-indent: -3000px;
overflow: hidden;
cursor: default;
opacity: 0.3;
}
.active.selector-add,
.active.selector-remove {
opacity: 1;
}
.active.selector-add:hover,
.active.selector-remove:hover {
cursor: pointer;
}
.selector-add {
background: url(../img/selector-icons.svg) 0 -96px no-repeat;
}
.active.selector-add:focus,
.active.selector-add:hover {
background-position: 0 -112px;
}
.selector-remove {
background: url(../img/selector-icons.svg) 0 -64px no-repeat;
}
.active.selector-remove:focus,
.active.selector-remove:hover {
background-position: 0 -80px;
}
a.selector-chooseall,
a.selector-clearall {
display: inline-block;
height: 16px;
text-align: left;
margin: 1px auto 3px;
overflow: hidden;
font-weight: bold;
line-height: 16px;
color: #666;
text-decoration: none;
opacity: 0.3;
}
a.active.selector-chooseall:focus,
a.active.selector-clearall:focus,
a.active.selector-chooseall:hover,
a.active.selector-clearall:hover {
color: #447e9b;
}
a.active.selector-chooseall,
a.active.selector-clearall {
opacity: 1;
}
a.active.selector-chooseall:hover,
a.active.selector-clearall:hover {
cursor: pointer;
}
a.selector-chooseall {
padding: 0 18px 0 0;
background: url(../img/selector-icons.svg) right -160px no-repeat;
cursor: default;
}
a.active.selector-chooseall:focus,
a.active.selector-chooseall:hover {
background-position: 100% -176px;
}
a.selector-clearall {
padding: 0 0 0 18px;
background: url(../img/selector-icons.svg) 0 -128px no-repeat;
cursor: default;
}
a.active.selector-clearall:focus,
a.active.selector-clearall:hover {
background-position: 0 -144px;
}
.selector .search-label-icon {
height: 0;
}
#user_form input[type="password"] {
width: 100%;
}
.control-label {
margin-top: 7px;
}
.help-block,
.timezonewarning {
font-size: .8em;
color: #859099;
font-style: italic;
}
.dashboard tbody tr:first-child td {
border-top: none;
}
.vTimeField {
margin-top: 10px;
}
.vTimeField,
.vDateField {
min-width: 200px;
}
.date-icon::before,
.clock-icon::before {
font-family: "Font Awesome 5 Free" !important;
}
.timelist li {
list-style-type: none;
}
.timelist {
margin: 0;
padding: 0;
}
body.no-sidebar .content-wrapper,
body.no-sidebar .main-footer,
body.no-sidebar .main-header {
margin-left: 0;
}
.vCheckboxLabel.inline {
vertical-align: top;
color: red;
margin-bottom: 0;
}
.inline-related .card-header>span {
float: right;
}
.ui-customiser .menu-items div {
width: 40px;
height: 20px;
border-radius: 25px;
margin-right: 10px;
margin-bottom: 10px;
opacity: 0.8;
cursor: pointer;
}
.ui-customiser select {
width: 100%;
height: auto;
padding: 6px 2px;
}
.control-sidebar-content label {
vertical-align: top;
}
.ui-customiser .menu-items div.inactive {
opacity: 0.3;
}
.ui-customiser .menu-items div.active {
opacity: 1;
border: 1px solid white;
}
.timeline-item {
word-break: break-word;
}
.navbar-nav .brand-link {
padding-top: 3px;
}
.breadcrumb {
background: transparent;
margin: 0;
}
.breadcrumb-item+.breadcrumb-item::before {
content: "\203A";
}
.login-box,
.register-box {
width: 500px;
max-width: 100%;
}
#jazzy-collapsible .collapsible-header:hover {
background: #007bff;
color: white;
}
#jazzy-collapsible .collapsible-header {
cursor: pointer;
}
#jazzy-carousel .carousel-indicators li {
background-color: #007bfe;
}
#jazzy-carousel .carousel-indicators {
position: initial;
}
form ul.radiolist li {
list-style-type: none;
}
form ul.radiolist label {
float: none;
display: inline;
}
form ul.radiolist input[type="radio"] {
margin: -2px 4px 0 0;
padding: 0;
}
form ul.inline {
margin-left: 0;
padding: 0;
}
form ul.inline li {
float: left;
padding-right: 7px;
}
.content-wrapper>.content {
padding: 1rem 2rem;
}
.navbar {
padding: .5rem 2rem;
}
.main-footer {
color: #869099;
padding: 1rem 2rem;
font-size: 14px;
}
.page-actions > a {
margin-right:0.25rem;
margin-left: 0.25rem;
}
#jazzy-actions.sticky-top {
top: 10px;
}
body.layout-navbar-fixed #jazzy-actions.sticky-top {
top: 67px;
}
/* stacked inlines */
a.inline-deletelink:hover {
background-color: #c82333;
border-color: #bd2130;
}
a.inline-deletelink {
float: right;
padding: 3px 5px;
margin: 10px;
background-color: #dc3545;
border-radius: .25rem;
color: white !important;
border: 1px solid #dc3545;
transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
/* end stacked inlines */
/* Support for django-mptt */
#result_list .field-tree_actions {
width: calc(40px + 2.25rem);
}
#result_list .field-tree_actions>div {
margin-top: 0;
}
/* End support for django-mptt */
/* modal tweaks */
.modal.modal-wide .modal-dialog {
width: 50%;
max-width: inherit;
}
.modal-wide .modal-body {
overflow-y: auto;
}
iframe.related-iframe {
width: 100%;
height: 450px;
}
/* Blur background when using modal */
.modal-open .wrapper {
-webkit-filter: blur(1px);
-moz-filter: blur(1px);
-o-filter: blur(1px);
-ms-filter: blur(1px);
filter: blur(1px);
}
/* end modal tweaks */
.control-sidebar {
overflow: hidden scroll;
}
/* tweaks to allow bootstrap styling */
body.jazzmin-login-page {
-ms-flex-align: center;
align-items: center;
display: -ms-flexbox;
display: flex;
-ms-flex-direction: column;
flex-direction: column;
height: 100vh;
-ms-flex-pack: center;
justify-content: center;
}
.callout {
color: black;
}
/* sidebar scrolling */
.layout-fixed #jazzy-sidebar {
top: 0;
bottom: 0;
/* Enable y scroll */
overflow-y: scroll;
/* May inherit scroll, so we need to explicitly hide */
overflow-x: hidden;
}
/* calculate height to fit content, we don't to enable scrolling if the content fits */
.layout-fixed #jazzy-sidebar .sidebar {
height: auto !important;
}
/* Hide scrollbar */
.layout-fixed #jazzy-sidebar {
scrollbar-width: none;
}
.layout-fixed #jazzy-sidebar::-webkit-scrollbar {
width: 0;
}
/* nav-item will overflow container in width if scrollbar is visible */
#jazzy-sidebar .nav-sidebar > .nav-item {
width: 100%;
}
/* tweeks for django-filer*/
.navigator-top-nav + #content-main {
float: left;
width: 100%;
}

View File

@@ -0,0 +1,14 @@
<svg width="15" height="60" viewBox="0 0 1792 7168" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="previous">
<path d="M1037 1395l102-102q19-19 19-45t-19-45l-307-307 307-307q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-454 454q-19 19-19 45t19 45l454 454q19 19 45 19t45-19zm627-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="next">
<path d="M845 1395l454-454q19-19 19-45t-19-45l-454-454q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l307 307-307 307q-19 19-19 45t19 45l102 102q19 19 45 19t45-19zm819-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
</defs>
<use xlink:href="#previous" x="0" y="0" fill="#333333" />
<use xlink:href="#previous" x="0" y="1792" fill="#000000" />
<use xlink:href="#next" x="0" y="3584" fill="#333333" />
<use xlink:href="#next" x="0" y="5376" fill="#000000" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -0,0 +1,9 @@
<svg width="16" height="32" viewBox="0 0 1792 3584" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="icon">
<path d="M192 1664h288v-288h-288v288zm352 0h320v-288h-320v288zm-352-352h288v-320h-288v320zm352 0h320v-320h-320v320zm-352-384h288v-288h-288v288zm736 736h320v-288h-320v288zm-384-736h320v-288h-320v288zm768 736h288v-288h-288v288zm-384-352h320v-320h-320v320zm-352-864v-288q0-13-9.5-22.5t-22.5-9.5h-64q-13 0-22.5 9.5t-9.5 22.5v288q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5-9.5t9.5-22.5zm736 864h288v-320h-288v320zm-384-384h320v-288h-320v288zm384 0h288v-288h-288v288zm32-480v-288q0-13-9.5-22.5t-22.5-9.5h-64q-13 0-22.5 9.5t-9.5 22.5v288q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5-9.5t9.5-22.5zm384-64v1280q0 52-38 90t-90 38h-1408q-52 0-90-38t-38-90v-1280q0-52 38-90t90-38h128v-96q0-66 47-113t113-47h64q66 0 113 47t47 113v96h384v-96q0-66 47-113t113-47h64q66 0 113 47t47 113v96h128q52 0 90 38t38 90z"/>
</g>
</defs>
<use xlink:href="#icon" x="0" y="0" fill="#447e9b" />
<use xlink:href="#icon" x="0" y="1792" fill="#003366" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,3 @@
<svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path fill="#efb80b" d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"/>
</svg>

After

Width:  |  Height:  |  Size: 380 B

View File

@@ -0,0 +1,34 @@
<svg width="16" height="192" viewBox="0 0 1792 21504" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="up">
<path d="M1412 895q0-27-18-45l-362-362-91-91q-18-18-45-18t-45 18l-91 91-362 362q-18 18-18 45t18 45l91 91q18 18 45 18t45-18l189-189v502q0 26 19 45t45 19h128q26 0 45-19t19-45v-502l189 189q19 19 45 19t45-19l91-91q18-18 18-45zm252 1q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="down">
<path d="M1412 897q0-27-18-45l-91-91q-18-18-45-18t-45 18l-189 189v-502q0-26-19-45t-45-19h-128q-26 0-45 19t-19 45v502l-189-189q-19-19-45-19t-45 19l-91 91q-18 18-18 45t18 45l362 362 91 91q18 18 45 18t45-18l91-91 362-362q18-18 18-45zm252-1q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="left">
<path d="M1408 960v-128q0-26-19-45t-45-19h-502l189-189q19-19 19-45t-19-45l-91-91q-18-18-45-18t-45 18l-362 362-91 91q-18 18-18 45t18 45l91 91 362 362q18 18 45 18t45-18l91-91q18-18 18-45t-18-45l-189-189h502q26 0 45-19t19-45zm256-64q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="right">
<path d="M1413 896q0-27-18-45l-91-91-362-362q-18-18-45-18t-45 18l-91 91q-18 18-18 45t18 45l189 189h-502q-26 0-45 19t-19 45v128q0 26 19 45t45 19h502l-189 189q-19 19-19 45t19 45l91 91q18 18 45 18t45-18l362-362 91-91q18-18 18-45zm251 0q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="clearall">
<path transform="translate(336, 336) scale(0.75)" d="M1037 1395l102-102q19-19 19-45t-19-45l-307-307 307-307q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-454 454q-19 19-19 45t19 45l454 454q19 19 45 19t45-19zm627-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
<g id="chooseall">
<path transform="translate(336, 336) scale(0.75)" d="M845 1395l454-454q19-19 19-45t-19-45l-454-454q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l307 307-307 307q-19 19-19 45t19 45l102 102q19 19 45 19t45-19zm819-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
</g>
</defs>
<use xlink:href="#up" x="0" y="0" fill="#666666" />
<use xlink:href="#up" x="0" y="1792" fill="#447e9b" />
<use xlink:href="#down" x="0" y="3584" fill="#666666" />
<use xlink:href="#down" x="0" y="5376" fill="#447e9b" />
<use xlink:href="#left" x="0" y="7168" fill="#666666" />
<use xlink:href="#left" x="0" y="8960" fill="#447e9b" />
<use xlink:href="#right" x="0" y="10752" fill="#666666" />
<use xlink:href="#right" x="0" y="12544" fill="#447e9b" />
<use xlink:href="#clearall" x="0" y="14336" fill="#666666" />
<use xlink:href="#clearall" x="0" y="16128" fill="#447e9b" />
<use xlink:href="#chooseall" x="0" y="17920" fill="#666666" />
<use xlink:href="#chooseall" x="0" y="19712" fill="#447e9b" />
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,151 @@
(function($) {
'use strict';
function FixSelectorHeight() {
$('.selector .selector-chosen').each(function () {
let selector_chosen = $(this);
let selector_available = selector_chosen.siblings('.selector-available');
let selector_chosen_select = selector_chosen.find('select').first();
let selector_available_select = selector_available.find('select').first();
let selector_available_filter = selector_available.find('p.selector-filter').first();
selector_chosen_select.height(selector_available_select.height() + selector_available_filter.outerHeight());
selector_chosen_select.css('border-top', selector_chosen_select.css('border-bottom'));
});
}
function handleCarousel($carousel) {
const errors = $('.errorlist li', $carousel);
const hash = document.location.hash;
// If we have errors, open that tab first
if (errors.length) {
const errorCarousel = errors.eq(0).closest('.carousel-item');
$carousel.carousel(errorCarousel.data('carouselid'));
$('.carousel-fieldset-label', $carousel).text(errorCarousel.data()["label"]);
} else if (hash) {
// If we have a tab hash, open that
const activeCarousel = $('.carousel-item[data-target="' + hash + '"]', $carousel);
$carousel.carousel(activeCarousel.data()["carouselid"]);
$('.carousel-fieldset-label', $carousel).text(activeCarousel.data()["label"]);
}
// Update page hash/history on slide
$carousel.on('slide.bs.carousel', function (e) {
FixSelectorHeight();
// call resize in change view after tab switch
window.dispatchEvent(new Event('resize'));
if (e.relatedTarget.dataset.hasOwnProperty("label")) {
$('.carousel-fieldset-label', $carousel).text(e.relatedTarget.dataset.label);
}
const hash = e.relatedTarget.dataset.target;
if (history.pushState) {
history.pushState(null, null, hash);
} else {
location.hash = hash;
}
});
}
function handleTabs($tabs) {
const errors = $('.change-form .errorlist li');
const hash = document.location.hash;
// If we have errors, open that tab first
if (errors.length) {
const tabId = errors.eq(0).closest('.tab-pane').attr('id');
$('a[href="#' + tabId + '"]').tab('show');
} else if (hash) {
// If we have a tab hash, open that
$('a[href="' + hash + '"]', $tabs).tab('show');
}
// Change hash for page-reload
$('a', $tabs).on('shown.bs.tab', function (e) {
FixSelectorHeight();
// call resize in change view after tab switch
window.dispatchEvent(new Event('resize'));
e.preventDefault();
if (history.pushState) {
history.pushState(null, null, e.target.hash);
} else {
location.hash = e.target.hash;
}
});
}
function handleCollapsible($collapsible) {
const errors = $('.errorlist li', $collapsible);
const hash = document.location.hash;
// If we have errors, open that tab first
if (errors.length) {
$('.panel-collapse', $collapsible).collapse('hide');
errors.eq(0).closest('.panel-collapse').collapse('show');
} else if (hash) {
// If we have a tab hash, open that
$('.panel-collapse', $collapsible).collapse('hide');
$(hash, $collapsible).collapse('show');
}
// Change hash for page-reload
$collapsible.on('shown.bs.collapse', function (e) {
FixSelectorHeight();
// call resize in change view after tab switch
window.dispatchEvent(new Event('resize'));
if (history.pushState) {
history.pushState(null, null, '#' + e.target.id);
} else {
location.hash = '#' + e.target.id;
}
});
}
function applySelect2() {
// Apply select2 to any select boxes that don't yet have it
// and are not part of the django's empty-form inline
const noSelect2 = '.empty-form select, .select2-hidden-accessible, .selectfilter, .selector-available select, .selector-chosen select, select[data-autocomplete-light-function=select2]';
$('select').not(noSelect2).select2({ width: 'element' });
}
$(document).ready(function () {
const $carousel = $('#content-main form #jazzy-carousel');
const $tabs = $('#content-main form #jazzy-tabs');
const $collapsible = $('#content-main form #jazzy-collapsible');
// Ensure all raw_id_fields have the search icon in them
$('.related-lookup').append('<i class="fa fa-search"></i>');
// Style the inline fieldset button
$('.inline-related fieldset.module .add-row a').addClass('btn btn-sm btn-default float-right');
$('div.add-row>a').addClass('btn btn-sm btn-default float-right');
// Ensure we preserve the tab the user was on using the url hash, even on page reload
if ($tabs.length) { handleTabs($tabs); }
else if ($carousel.length) { handleCarousel($carousel); }
else if ($collapsible.length) { handleCollapsible($collapsible); }
applySelect2();
$('body').on('change', '.related-widget-wrapper select', function(e) {
const event = $.Event('django:update-related');
$(this).trigger(event);
if (!event.isDefaultPrevented() && typeof(window.updateRelatedObjectLinks) !== 'undefined') {
updateRelatedObjectLinks(this);
}
});
});
// Apply select2 to all select boxes when new inline row is created
django.jQuery(document).on('formset:added', applySelect2);
})(jQuery);

View File

@@ -0,0 +1,64 @@
(function($) {
'use strict';
$.fn.search_filters = function () {
$(this).change(function () {
const $field = $(this);
const $option = $field.find('option:selected');
const select_name = $option.data('name');
if (select_name) {
$field.attr('name', select_name);
} else {
$field.removeAttr('name');
}
});
$(this).trigger('change');
};
function getMinimuInputLength(element) {
return window.filterInputLength[element.data('name')] ?? window.filterInputLengthDefault;
}
function searchFilters() {
// Make search filters select2 and ensure they work for filtering
const $ele = $('.search-filter');
$ele.search_filters();
$ele.each(function () {
const $this = $(this);
$this.select2({ width: '100%', minimumInputLength: getMinimuInputLength($this) });
});
// Use select2 for mptt dropdowns
const $mptt = $('.search-filter-mptt');
if ($mptt.length) {
$mptt.search_filters();
$mptt.select2({
width: '100%',
minimumInputLength: getMinimuInputLength($mptt),
templateResult: function (data) {
// https://stackoverflow.com/questions/30820215/selectable-optgroups-in-select2#30948247
// rewrite templateresult for build tree hierarchy
if (!data.element) {
return data.text;
}
const $element = $(data.element);
let $wrapper = $('<span></span>');
$wrapper.attr('style', $($element[0]).attr('style'));
$wrapper.text(data.text);
return $wrapper;
},
});
}
}
$(document).ready(function () {
// Ensure all raw_id_fields have the search icon in them
$('.related-lookup').append('<i class="fa fa-search"></i>')
// Allow for styling of selects
$('.actions select').addClass('form-control').select2({ width: 'element' });
searchFilters();
});
})(jQuery);

67
static/jazzmin/js/main.js Normal file
View File

@@ -0,0 +1,67 @@
(function($) {
'use strict';
function setCookie(key, value) {
const expires = new Date();
expires.setTime(expires.getTime() + (value * 24 * 60 * 60 * 1000));
document.cookie = key + '=' + value + ';expires=' + expires.toUTCString() + '; SameSite=Strict;path=/';
}
function getCookie(key) {
const keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
return keyValue ? keyValue[2] : null;
}
function handleMenu() {
$('[data-widget=pushmenu]').bind('click', function () {
const menuClosed = getCookie('jazzy_menu') === 'closed';
if (!menuClosed) {
setCookie('jazzy_menu', 'closed');
} else {
setCookie('jazzy_menu', 'open');
}
});
}
function setActiveLinks() {
/*
Set the currently active menu item based on the current url, or failing that, find the parent
item from the breadcrumbs
*/
const url = window.location.pathname;
const $breadcrumb = $('.breadcrumb a').last();
const $link = $('a[href="' + url + '"]');
const $parent_link = $('a[href="' + $breadcrumb.attr('href') + '"]');
if ($link.length) {
$link.addClass('active');
} else if ($parent_link.length) {
$parent_link.addClass('active');
};
const $a_active = $('a.nav-link.active');
const $main_li_parent = $a_active.closest('li.nav-item.has-treeview');
const $ul_child = $main_li_parent.children('ul');
$ul_child.show();
$main_li_parent.addClass('menu-is-opening menu-open');
};
$(document).ready(function () {
// Set active status on links
setActiveLinks()
// When we use the menu, store its state in a cookie to preserve it
handleMenu();
// Add minimal changelist styling to templates that we have been unable to override (e.g MPTT)
// Needs to be here and not in change_list.js because this is the only JS we are guaranteed to run
// (as its included in base.html)
const $changeListTable = $('#changelist .results table');
if ($changeListTable.length && !$changeListTable.hasClass('table table-striped')) {
$changeListTable.addClass('table table-striped');
};
});
})(jQuery);

View File

@@ -0,0 +1,188 @@
(function($) {
'use strict';
let relatedModalCounter = 0;
function checkIfInIframe() {
return window.top !== window.self;
}
// create the function that will close the modal
function dismissModal() {
if (checkIfInIframe()) {
const parentWindow = window.parent;
parentWindow.dismissModal();
return;
}
$('.related-modal-' + relatedModalCounter).modal('hide');
relatedModalCounter-=1;
}
// create the function that will show the modal
function showModal(title, body, e) {
if (checkIfInIframe()) {
const parentWindow = window.parent;
parentWindow.showModal(title, body, e);
return;
}
relatedModalCounter+=1;
$.showModal({
title: title,
body: body,
backdrop: false,
modalDialogClass: "modal-dialog-centered modal-lg",
modalClass: "fade modal-wide related-modal-" + relatedModalCounter,
onDispose: function() {
// add focus to the previous modal (if exists) when the current one is closed
var lastModal = $("div[class*='related-modal-']").last();
if (lastModal) {
lastModal.focus();
}
}
});
const modalEl = $("div[class*='related-modal-']");
const iframeEl = modalEl.find('#related-modal-iframe');
if (e.data.lookup === true) {
// set current window as iframe opener because
// the callback is called on the opener window
iframeEl.on('load', function() {
const iframeObj = $(this).get(0);
const iframeWindow = iframeObj.contentWindow;
iframeWindow.opener = window;
});
}
}
function dismissRelatedLookupModal(win, chosenId) {
const windowName = win.name;
const widgetName = windowName.replace(/^(change|add|delete|lookup)_/, '');
let widgetEl;
if (checkIfInIframe) {
// select second to last iframe in the main parent document
const secondLastIframe = $('iframe.related-iframe', win.parent.document).eq(-2);
let documentContext;
// if second to last iframe exists get its contents
if (secondLastIframe.length) {
documentContext = secondLastIframe.contents();
// else get main parent document
} else {
documentContext = $(win.parent.document);
}
// find and select widget from the specified document context
widgetEl = documentContext.find('#' + widgetName);
// else select widget from the main document
} else {
widgetEl = $('#' + widgetName);
}
const widgetVal = widgetEl.val();
if (widgetEl.hasClass('vManyToManyRawIdAdminField') && Boolean(widgetVal)) {
widgetEl.val(widgetVal + ', ' + chosenId);
} else {
widgetEl.val(chosenId);
}
dismissModal();
}
// assign functions to global variables
window.dismissRelatedObjectModal = dismissModal;
window.dismissRelatedLookupPopup = dismissRelatedLookupModal;
window.showModal = showModal;
function presentRelatedObjectModal(e) {
let linkEl = $(this);
let href = (linkEl.attr('href') || '');
if (href === '') {
return;
}
// open the popup as modal
e.preventDefault();
e.stopImmediatePropagation();
// remove focus from clicked link
linkEl.blur();
// use the clicked link id as iframe name
// it will be available as window.name in the loaded iframe
let iframeName = linkEl.attr('id');
let iframeSrc = href;
const modalTitle = linkEl.attr('title');
if (e.data.lookup !== true) {
// browsers stop loading nested iframes having the same src url
// create a random parameter and append it to the src url to prevent it
// this workaround doesn't work with related lookup url
let iframeSrcRandom = String(Math.round(Math.random() * 999999));
if (iframeSrc.indexOf('?') === -1) {
iframeSrc += '?_modal=' + iframeSrcRandom;
} else {
iframeSrc += '&_modal=' + iframeSrcRandom;
}
}
if (iframeSrc.indexOf('_popup=1') === -1) {
if (iframeSrc.indexOf('?') === -1) {
iframeSrc += '?_popup=1';
} else {
iframeSrc += '&_popup=1';
}
}
// build the iframe html
let iframeHTML = '<iframe id="related-modal-iframe" name="' + iframeName + '" src="' + iframeSrc + '" frameBorder="0" class="related-iframe"></iframe>';
// the modal css class
let iframeInternalModalClass = 'related-modal';
// if the current window is inside an iframe, it means that it is already in a modal,
// append an additional css class to the modal to offer more customization
if (window.top !== window.self) {
iframeInternalModalClass += ' related-modal__nested';
}
// open the modal using dynamic bootstrap modal
showModal(modalTitle, iframeHTML, e);
return false;
}
// listen click events on related links
function presentRelatedObjectModalOnClickOn(selector, lookup) {
let el = $(selector);
el.removeAttr('onclick');
el.unbind('click');
el.click({lookup: lookup}, presentRelatedObjectModal);
}
function init() {
presentRelatedObjectModalOnClickOn('a.related-widget-wrapper-link', false);
// raw_id_fields support
presentRelatedObjectModalOnClickOn('a.related-lookup', true);
// django-dynamic-raw-id support - #61
// https://github.com/lincolnloop/django-dynamic-raw-id
presentRelatedObjectModalOnClickOn('a.dynamic_raw_id-related-lookup', true);
}
$(document).ready(function(){
init()
});
django.jQuery(document).on('formset:added', init);
})(jQuery);

View File

@@ -0,0 +1,343 @@
(function ($) {
'use strict';
const $body = $('body');
const $footer = $('footer');
const $sidebar_ul = $('aside#jazzy-sidebar nav ul:first-child');
const $sidebar = $('aside#jazzy-sidebar');
const $navbar = $('nav#jazzy-navbar');
const $logo = $('#jazzy-logo');
const $actions = $('#jazzy-actions');
const buttons = [
"primary",
"secondary",
"info",
"warning",
"danger",
"success",
]
const darkThemes = ["darkly", "cyborg", "slate", "solar", "superhero"]
window.ui_changes = window.ui_changes || {'button_classes': {}};
function miscListeners() {
$('#footer-fixed').on('click', function () {
$body.toggleClass('layout-footer-fixed');
if (this.checked) {
$('#layout-boxed:checked').click();
}
window.ui_changes['footer_fixed'] = this.checked;
});
$('#layout-boxed').on('click', function () {
$body.toggleClass('layout-boxed');
// We cannot combine these options with layout boxed
if (this.checked) {
$('#navbar-fixed:checked').click();
$('#footer-fixed:checked').click();
}
window.ui_changes['layout_boxed'] = this.checked;
});
$('#actions-fixed').on('click', function () {
$actions.toggleClass('sticky-top');
window.ui_changes['actions_sticky_top'] = this.checked;
});
// Colour pickers
$('#accent-colours div').on('click', function () {
$(this).removeClass('inactive').addClass('active').parent().find(
'div'
).not(this).removeClass('active').addClass('inactive');
const newClasses = $(this).data('classes');
$body.removeClass(function (index, className) {
return (className.match(/(^|\s)accent-\S+/g) || []).join(' ');
}).addClass(newClasses);
window.ui_changes['accent'] = newClasses;
});
$('#brand-logo-variants div').on('click', function () {
$(this).removeClass('inactive').addClass('active').parent().find(
'div'
).not(this).removeClass('active').addClass('inactive');
let newClasses = $(this).data('classes');
$logo.removeClass(function (index, className) {
return (className.match(/(^|\s)navbar-\S+/g) || []).join(' ');
}).addClass(newClasses);
if (newClasses === "") {
newClasses = false;
$(this).parent().find('div').removeClass('active inactive');
}
window.ui_changes['brand_colour'] = newClasses;
});
// show code
$("#codeBox").on('show.bs.modal', function () {
$('.modal-body code', this).html(
'JAZZMIN_UI_TWEAKS = ' + JSON.stringify(
window.ui_changes, null, 4
).replace(
/true/g, 'True'
).replace(
/false/g, 'False'
).replace(
/null/g, 'None'
)
);
});
}
function themeSpecificTweaks(theme) {
if (darkThemes.indexOf(theme) > -1) {
$('#navbar-variants .bg-dark').click();
$("#jazzmin-btn-style-primary").val('btn-primary').change();
$("#jazzmin-btn-style-secondary").val('btn-secondary').change();
$body.addClass('dark-mode');
} else {
$('#navbar-variants .bg-white').click();
$("#jazzmin-btn-style-primary").val('btn-outline-primary').change();
$("#jazzmin-btn-style-secondary").val('btn-outline-secondary').change();
$body.removeClass('dark-mode');
}
}
function themeChooserListeners() {
// Theme chooser (standard)
$("#jazzmin-theme-chooser").on('change', function () {
let $themeCSS = $('#jazzmin-theme');
// If we are using the default theme, there will be no theme css, just the bundled one in adminlte
if (!$themeCSS.length) {
const staticSrc = $('#adminlte-css').attr('href').split('vendor')[0]
$themeCSS = $('<link>').attr({
'href': staticSrc + 'vendor/bootswatch/default/bootstrap.min.css',
'rel': 'stylesheet',
'id': 'jazzmin-theme'
}).appendTo('head');
}
const currentSrc = $themeCSS.attr('href');
const currentTheme = currentSrc.split('/')[4];
let newTheme = $(this).val();
$themeCSS.attr('href', currentSrc.replace(currentTheme, newTheme));
$body.removeClass (function (index, className) {
return (className.match (/(^|\s)theme-\S+/g) || []).join(' ');
});
$body.addClass('theme-' + newTheme);
themeSpecificTweaks(newTheme);
window.ui_changes['theme'] = newTheme;
});
// Theme chooser (dark mode)
$("#jazzmin-dark-mode-theme-chooser").on('change', function () {
let $themeCSS = $('#jazzmin-dark-mode-theme');
// If we are using the default theme, there will be no theme css, just the bundled one in adminlte
if (this.value === "") {
$themeCSS.remove();
window.ui_changes['dark_mode_theme'] = null;
return
}
if (!$themeCSS.length) {
const staticSrc = $('#adminlte-css').attr('href').split('vendor')[0]
$themeCSS = $('<link>').attr({
'href': staticSrc + 'vendor/bootswatch/darkly/bootstrap.min.css',
'rel': 'stylesheet',
'id': 'jazzmin-dark-mode-theme',
'media': '(prefers-color-scheme: dark)'
}).appendTo('head');
}
const currentSrc = $themeCSS.attr('href');
const currentTheme = currentSrc.split('/')[4];
const newTheme = $(this).val();
$themeCSS.attr('href', currentSrc.replace(currentTheme, newTheme));
themeSpecificTweaks(newTheme);
window.ui_changes['dark_mode_theme'] = newTheme;
});
}
function navBarTweaksListeners() {
$('#navbar-fixed').on('click', function () {
$body.toggleClass('layout-navbar-fixed');
if (this.checked) {$('#layout-boxed:checked').click();}
window.ui_changes['navbar_fixed'] = this.checked;
});
$('#no-navbar-border').on('click', function () {
$navbar.toggleClass('border-bottom-0');
window.ui_changes['no_navbar_border'] = $navbar.hasClass('border-bottom-0');
});
// Colour picker
$('#navbar-variants div').on('click', function () {
$(this).removeClass('inactive').addClass('active').parent().find(
'div'
).not(this).removeClass('active').addClass('inactive');
const newClasses = $(this).data('classes');
$navbar.removeClass(function (index, className) {
return (className.match(/(^|\s)navbar-\S+/g) || []).join(' ');
}).addClass('navbar-expand ' + newClasses);
window.ui_changes['navbar'] = newClasses;
});
}
function sideBarTweaksListeners() {
$('#sidebar-nav-flat-style').on('click', function () {
$sidebar_ul.toggleClass('nav-flat');
window.ui_changes['sidebar_nav_flat_style'] = this.checked;
});
$('#sidebar-nav-legacy-style').on('click', function () {
$sidebar_ul.toggleClass('nav-legacy');
window.ui_changes['sidebar_nav_legacy_style'] = this.checked;
});
$('#sidebar-nav-compact').on('click', function () {
$sidebar_ul.toggleClass('nav-compact');
window.ui_changes['sidebar_nav_compact_style'] = this.checked;
});
$('#sidebar-nav-child-indent').on('click', function () {
$sidebar_ul.toggleClass('nav-child-indent');
window.ui_changes['sidebar_nav_child_indent'] = this.checked;
});
$('#main-sidebar-disable-hover-focus-auto-expand').on('click', function () {
$sidebar.toggleClass('sidebar-no-expand');
window.ui_changes['sidebar_disable_expand'] = this.checked;
});
$('#sidebar-fixed').on('click', function () {
$body.toggleClass('layout-fixed');
window.ui_changes['sidebar_fixed'] = this.checked;
});
// Colour pickers
$('#dark-sidebar-variants div, #light-sidebar-variants div').on('click', function () {
$(this).removeClass('inactive').addClass('active').parent().find(
'div'
).not(this).removeClass('active').addClass('inactive');
const newClasses = $(this).data('classes');
$sidebar.removeClass(function (index, className) {
return (className.match(/(^|\s)sidebar-[\S|-]+/g) || []).join(' ');
}).addClass(newClasses);
window.ui_changes['sidebar'] = newClasses.trim();
});
}
function smallTextListeners() {
$('#navbar-small-text').on('click', function () {
$navbar.toggleClass('text-sm');
window.ui_changes['navbar_small_text'] = this.checked;
});
$('#brand-small-text').on('click', function () {
$logo.toggleClass('text-sm');
window.ui_changes['brand_small_text'] = this.checked;
});
$('#body-small-text').on('click', function () {
$body.toggleClass('text-sm');
window.ui_changes['body_small_text'] = this.checked;
const $smallTextControls = $('#navbar-small-text, #brand-small-text, #footer-small-text, #sidebar-nav-small-text');
if (this.checked) {
window.ui_changes['navbar_small_text'] = false;
window.ui_changes['brand_small_text'] = false;
window.ui_changes['footer_small_text'] = false;
window.ui_changes['sidebar_nav_small_text'] = false;
$smallTextControls.prop({'checked': false, 'disabled': 'disabled'});
} else {
$smallTextControls.prop({'checked': false, 'disabled': ''});
}
});
$('#footer-small-text').on('click', function () {
$footer.toggleClass('text-sm');
window.ui_changes['footer_small_text'] = this.checked;
});
$('#sidebar-nav-small-text').on('click', function () {
$sidebar_ul.toggleClass('text-sm');
window.ui_changes['sidebar_nav_small_text'] = this.checked;
});
}
function buttonStyleListeners() {
buttons.forEach(function(btn) {
$("#jazzmin-btn-style-" + btn).on('change', function () {
const btnClasses = ['btn-' + btn, 'btn-outline-' + btn];
const selectorClasses = '.btn-' + btn + ', .btn-outline-' + btn;
$(selectorClasses).removeClass(btnClasses).addClass(this.value);
window.ui_changes['button_classes'][btn] = this.value;
});
});
}
function setFromExisting() {
$('#jazzmin-theme-chooser').val(window.ui_changes['theme']);
$('#jazzmin-dark-mode-theme-chooser').val(window.ui_changes['dark_mode_theme']);
$('#theme-condition').val(window.ui_changes['theme_condition']);
$('#body-small-text').get(0).checked = window.ui_changes['body_small_text'];
$('#footer-small-text').get(0).checked = window.ui_changes['footer_small_text'];
$('#sidebar-nav-small-text').get(0).checked = window.ui_changes['sidebar_nav_small_text'];
$('#sidebar-nav-legacy-style').get(0).checked = window.ui_changes['sidebar_nav_legacy_style'];
$('#sidebar-nav-compact').get(0).checked = window.ui_changes['sidebar_nav_compact_style'];
$('#sidebar-nav-child-indent').get(0).checked = window.ui_changes['sidebar_nav_child_indent'];
$('#main-sidebar-disable-hover-focus-auto-expand').get(0).checked = window.ui_changes['sidebar_disable_expand'];
$('#no-navbar-border').get(0).checked = window.ui_changes['no_navbar_border'];
$('#navbar-small-text').get(0).checked = window.ui_changes['navbar_small_text'];
$('#brand-small-text').get(0).checked = window.ui_changes['brand_small_text'];
// deactivate colours
$('#navbar-variants div, #accent-colours div, #dark-sidebar-variants div, #light-sidebar-variants div, #brand-logo-variants div').addClass('inactive');
// set button styles
buttons.forEach(function(btn) {
$("#jazzmin-btn-style-" + btn).val(window.ui_changes['button_classes'][btn]);
});
// set colours
$('#navbar-variants div[data-classes="' + window.ui_changes['navbar'] + '"]').addClass('active');
$('#accent-colours div[data-classes="' + window.ui_changes['accent'] + '"]').addClass('active');
$('#dark-sidebar-variants div[data-classes="' + window.ui_changes['sidebar'] + '"]').addClass('active');
$('#light-sidebar-variants div[data-classes="' + window.ui_changes['sidebar'] + '"]').addClass('active');
$('#brand-logo-variants div[data-classes="' + window.ui_changes['brand_colour'] + '"]').addClass('active');
}
/*
Don't call if it is inside an iframe
*/
if (!$body.hasClass("popup")) {
setFromExisting();
themeChooserListeners();
miscListeners();
navBarTweaksListeners();
sideBarTweaksListeners();
smallTextListeners();
buttonStyleListeners();
}
})(jQuery);

View File

@@ -0,0 +1 @@
!function(o){"use strict";var s=0;function i(t){for(var e in this.props={title:"",body:"",footer:"",modalClass:"fade",modalDialogClass:"",options:null,onCreate:null,onDispose:null,onSubmit:null},t)this.props[e]=t[e];this.id="bootstrap-show-modal-"+s,s++,this.show()}i.prototype.createContainerElement=function(){var t=this;this.element=document.createElement("div"),this.element.id=this.id,this.element.setAttribute("class","modal "+this.props.modalClass),this.element.setAttribute("tabindex","-1"),this.element.setAttribute("role","dialog"),this.element.setAttribute("aria-labelledby",this.id),this.element.innerHTML='<div class="modal-dialog '+this.props.modalDialogClass+'" role="document"><div class="modal-content"><div class="modal-header"><h5 class="modal-title"></h5><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button></div><div class="modal-body"></div><div class="modal-footer"></div></div></div>',document.body.appendChild(this.element),this.titleElement=this.element.querySelector(".modal-title"),this.bodyElement=this.element.querySelector(".modal-body"),this.footerElement=this.element.querySelector(".modal-footer"),o(this.element).on("hidden.bs.modal",function(){t.dispose()}),this.props.onCreate&&this.props.onCreate(this)},i.prototype.show=function(){this.element?o(this.element).modal("show"):(this.createContainerElement(),this.props.options?o(this.element).modal(this.props.options):o(this.element).modal()),this.props.title?(o(this.titleElement).show(),this.titleElement.innerHTML=this.props.title):o(this.titleElement).hide(),this.props.body?(o(this.bodyElement).show(),this.bodyElement.innerHTML=this.props.body):o(this.bodyElement).hide(),this.props.footer?(o(this.footerElement).show(),this.footerElement.innerHTML=this.props.footer):o(this.footerElement).hide()},i.prototype.hide=function(){o(this.element).modal("hide")},i.prototype.dispose=function(){o(this.element).modal("dispose"),document.body.removeChild(this.element),this.props.onDispose&&this.props.onDispose(this)},o.extend({showModal:function(t){if(t.buttons){var e,o="";for(e in t.buttons){o+='<button type="button" class="btn btn-primary" data-value="'+e+'" data-dismiss="modal">'+t.buttons[e]+"</button>"}t.footer=o}return new i(t)},showAlert:function(t){return t.buttons={OK:"OK"},this.showModal(t)},showConfirm:function(t){return t.footer='<button class="btn btn-secondary btn-false btn-cancel">'+t.textFalse+'</button><button class="btn btn-primary btn-true">'+t.textTrue+"</button>",t.onCreate=function(e){o(e.element).on("click",".btn",function(t){t.preventDefault(),e.hide(),e.props.onSubmit(-1!==t.target.getAttribute("class").indexOf("btn-true"),e)})},this.showModal(t)}})}(jQuery);