mirror of
https://github.com/wagtail/wagtail.git
synced 2024-11-21 18:09:02 +01:00
Page editor underline tabs (#8266)
Co-authored-by: Thibaud Colas <thibaudcolas@gmail.com>
This commit is contained in:
parent
ec70921e52
commit
629ced01ca
@ -112,7 +112,11 @@ module.exports = {
|
||||
globals: { $: 'readonly' },
|
||||
},
|
||||
{
|
||||
files: ['wagtail/**/**'],
|
||||
files: [
|
||||
'wagtail/**/**',
|
||||
'client/src/entrypoints/documents/document-chooser-modal.js',
|
||||
'client/src/entrypoints/images/image-chooser-modal.js',
|
||||
],
|
||||
globals: {
|
||||
$: 'readonly',
|
||||
addMessage: 'readonly',
|
||||
|
@ -49,6 +49,7 @@ Changelog
|
||||
* Add the ability for choices to be separated by new lines instead of just commas within the form builder, commas will still be supported if used (Abdulmajeed Isa)
|
||||
* Add internationalisation UI to modeladmin (Andrés Martano)
|
||||
* Support chunking in `PageQuerySet.specific()` to reduce memory consumption (Andy Babic)
|
||||
* Implement new tabs design across the admin interface (Steven Steinwand)
|
||||
* Fix: When using `simple_translations` ensure that the user is redirected to the page edit view when submitting for a single locale (Mitchel Cabuloy)
|
||||
* Fix: When previewing unsaved changes to `Form` pages, ensure that all added fields are correctly shown in the preview (Joshua Munn)
|
||||
* Fix: When Documents (e.g. PDFs) have been configured to be served inline via `WAGTAILDOCS_CONTENT_TYPES` & `WAGTAILDOCS_INLINE_CONTENT_TYPES` ensure that the filename is correctly set in the `Content-Disposition` header so that saving the files will use the correct filename (John-Scott Atlakson)
|
||||
@ -68,6 +69,7 @@ Changelog
|
||||
* Fix: Page copy in Wagtail admin ignores `exclude_fields_in_copy` (John-Scott Atlakson)
|
||||
* Fix: Translation key `IntegrityError` when publishing pages with translatable `Orderable`s that were copied without being published (Kalob Taulien, Dan Braghis)
|
||||
* Fix: Ignore `GenericRelation` when copying pages (John-Scott Atlakson)
|
||||
* Fix: Implement ARIA tabs markup and keyboards interactions for admin tabs (Steven Steinwand)
|
||||
|
||||
|
||||
2.16.2 (11.04.2022)
|
||||
|
@ -69,28 +69,6 @@ header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.tab-merged {
|
||||
padding-inline-start: $desktop-nice-padding;
|
||||
padding-inline-end: $desktop-nice-padding;
|
||||
|
||||
.right:last-child {
|
||||
padding-inline-end: 0;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
.breadcrumb {
|
||||
padding-inline-start: calc(#{$desktop-nice-padding} - 8px);
|
||||
}
|
||||
}
|
||||
@include media-breakpoint-up(sm) {
|
||||
.breadcrumb {
|
||||
margin-inline-start: -$desktop-nice-padding;
|
||||
margin-inline-end: -$desktop-nice-padding;
|
||||
padding-inline-start: math.div($desktop-nice-padding, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.header-with-breadcrumb {
|
||||
padding-top: 0;
|
||||
|
||||
@ -103,7 +81,6 @@ header {
|
||||
}
|
||||
}
|
||||
|
||||
&.tab-merged,
|
||||
&.no-border {
|
||||
border: 0;
|
||||
|
||||
|
@ -124,10 +124,6 @@ $zindex-modal-background: 500;
|
||||
h1 {
|
||||
@apply w-text-white;
|
||||
}
|
||||
|
||||
&.tab-merged {
|
||||
padding-inline-start: 1.6em;
|
||||
}
|
||||
}
|
||||
|
||||
.header-title {
|
||||
@ -135,22 +131,12 @@ $zindex-modal-background: 500;
|
||||
padding-inline-start: 0 !important;
|
||||
margin-inline-start: -36px;
|
||||
}
|
||||
|
||||
.tab-merged .header-title {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
.modal-dialog {
|
||||
padding: 0 0 2em $menu-width;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
header.tab-merged {
|
||||
padding-inline-start: $desktop-nice-padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl) {
|
||||
|
@ -1,111 +1,4 @@
|
||||
.tab-nav {
|
||||
@apply w-bg-grey-50;
|
||||
@include row();
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
width: 33%;
|
||||
float: left;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
margin-inline-end: 2px;
|
||||
|
||||
&:first-of-type {
|
||||
padding-inline-start: $desktop-nice-padding;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
a {
|
||||
// border-top 0.3em is temporary until the new tab design is implemented
|
||||
@apply w-bg-primary w-border-t-[0.3em] w-border-primary-200;
|
||||
@include transition(border-color 0.2s ease);
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
padding: 0.6em 0.7em 0.8em;
|
||||
color: $color-white;
|
||||
max-height: 1.44em;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
color: $color-white;
|
||||
border-top-color: rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
}
|
||||
|
||||
a.errors {
|
||||
&:after {
|
||||
border-radius: 50px;
|
||||
box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.1);
|
||||
position: absolute;
|
||||
// Remove once we drop support for Safari 13.
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
right: -0.5em;
|
||||
inset-inline-end: -0.5em;
|
||||
top: -0.5em;
|
||||
z-index: 5;
|
||||
min-width: 0.9em;
|
||||
color: $color-white;
|
||||
background: $color-red;
|
||||
content: attr(data-count);
|
||||
padding: 0 0.3em;
|
||||
line-height: 1.4em;
|
||||
text-align: center;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
li.active a {
|
||||
box-shadow: none;
|
||||
color: $color-grey-1;
|
||||
background-color: $color-white;
|
||||
border-top: 0.3em solid $color-grey-1;
|
||||
}
|
||||
|
||||
// For cases where tab-nav should merge with header
|
||||
.page-editor & {
|
||||
&.merged {
|
||||
@apply w-pt-2 sm:w-pt-4;
|
||||
}
|
||||
}
|
||||
|
||||
&.merged {
|
||||
@apply w-mt-0;
|
||||
}
|
||||
|
||||
li.right {
|
||||
float: right;
|
||||
margin-inline-end: 0;
|
||||
margin-inline-start: 2px;
|
||||
}
|
||||
|
||||
li.wide {
|
||||
width: unset;
|
||||
}
|
||||
|
||||
.right {
|
||||
max-height: 1.44em;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
> section {
|
||||
display: none;
|
||||
padding-top: 1em;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.page-locked & {
|
||||
cursor: not-allowed;
|
||||
user-select: none;
|
||||
@ -116,53 +9,72 @@
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
.tab-nav {
|
||||
// For cases where tab-nav should merge with header
|
||||
&.merged {
|
||||
@apply w-bg-grey-50;
|
||||
}
|
||||
.w-tabs {
|
||||
&__wrapper {
|
||||
@apply w-mb-10 w-overflow-x-auto w-scrollbar-thin;
|
||||
}
|
||||
|
||||
li {
|
||||
width: auto;
|
||||
padding: 0;
|
||||
}
|
||||
&__list {
|
||||
@include nice-padding();
|
||||
@apply w-flex w-my-[3px] w-space-x-6 w-border-b w-border-grey-100 w-w-fit;
|
||||
}
|
||||
|
||||
a {
|
||||
padding-inline-start: $mobile-nice-padding;
|
||||
padding-inline-end: $mobile-nice-padding;
|
||||
}
|
||||
&__tab {
|
||||
@apply w-label-3
|
||||
w-box-border
|
||||
w-inline-flex
|
||||
w-text-grey-400
|
||||
hover:w-text-primary
|
||||
w-whitespace-nowrap
|
||||
w-py-4
|
||||
w-font-medium
|
||||
w-relative
|
||||
after:w-block
|
||||
after:w-w-0
|
||||
after:w-h-[2px]
|
||||
after:w-bg-primary
|
||||
after:w-absolute
|
||||
after:w-left-0
|
||||
after:-w-bottom-px
|
||||
after:w-transition-all
|
||||
motion-reduce:after:w-transition-none
|
||||
hover:after:w-w-full;
|
||||
|
||||
li.settings a {
|
||||
padding-inline-start: 2em;
|
||||
padding-inline-end: 2em;
|
||||
&[aria-selected='true'] {
|
||||
@apply after:w-w-full w-text-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content .tab-nav li {
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
&__errors {
|
||||
@apply w-hidden
|
||||
w-box-border
|
||||
w-w-4
|
||||
w-h-4
|
||||
w-text-[0.75rem]
|
||||
w-flex
|
||||
w-justify-center
|
||||
w-items-center
|
||||
w-font-bold
|
||||
w-bg-critical-200
|
||||
w-text-white
|
||||
w-border
|
||||
w-border-white
|
||||
w-rounded-full
|
||||
w-absolute
|
||||
w-top-[0.4375rem]
|
||||
-w-right-[0.9375rem];
|
||||
|
||||
&:first-of-type {
|
||||
padding-inline-start: $desktop-nice-padding;
|
||||
&--active {
|
||||
@apply w-flex;
|
||||
}
|
||||
}
|
||||
|
||||
// Optional animate attr for tabs to animate in
|
||||
&[data-tabs-animate] &__panel {
|
||||
@apply motion-reduce:w-transition-none w-transition w-duration-150 w-translate-y-1 w-opacity-0;
|
||||
|
||||
&.animate-in {
|
||||
@apply w-translate-y-0 w-opacity-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
// To allow tabs on the edit page to be editable
|
||||
.tab-nav li:first-of-type {
|
||||
padding-inline-start: 1.6em;
|
||||
}
|
||||
|
||||
.tab-nav li {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// Media for Windows High Contrast
|
||||
@media (forced-colors: $media-forced-colours) {
|
||||
.tab-nav li.active a {
|
||||
border-bottom: 0.3em solid $system-color-link-text;
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +154,6 @@ These are classes that provide overrides.
|
||||
@import 'overrides/utilities.dropdowns';
|
||||
@import 'overrides/utilities.focus';
|
||||
@import 'overrides/utilities.visuallyhidden';
|
||||
@import 'overrides/utilities.scrollbars';
|
||||
|
||||
// Legacy utilities
|
||||
@import 'overrides/utilities.legacy';
|
||||
|
@ -45,3 +45,8 @@ img {
|
||||
border-width: 0;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
::before,
|
||||
::after {
|
||||
--tw-content: '';
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
.u-scrollbar-thin {
|
||||
// Scrollbar styling for firefox
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color
|
||||
scrollbar-color: theme('colors.grey.100') theme('colors.white.DEFAULT');
|
||||
scrollbar-width: thin;
|
||||
|
||||
//Custom scrollbar styling for Safari & Chrome Windows / Mac / Android.
|
||||
&::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-button {
|
||||
@apply w-hidden;
|
||||
// Hide the scrollbar arrows on windows
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
@apply w-bg-grey-200 w-rounded-sm;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
@apply w-bg-white;
|
||||
}
|
||||
}
|
@ -202,7 +202,7 @@ export const Menu: React.FunctionComponent<MenuProps> = ({
|
||||
};
|
||||
|
||||
const className =
|
||||
'sidebar-main-menu u-scrollbar-thin' +
|
||||
'sidebar-main-menu w-scrollbar-thin' +
|
||||
(accountSettingsOpen ? ' sidebar-main-menu--open-footer' : '');
|
||||
|
||||
return (
|
||||
|
@ -4,7 +4,7 @@ exports[`Menu should render with the minimum required props 1`] = `
|
||||
<Fragment>
|
||||
<nav
|
||||
aria-label="Main menu"
|
||||
className="sidebar-main-menu u-scrollbar-thin"
|
||||
className="sidebar-main-menu w-scrollbar-thin"
|
||||
>
|
||||
<ul
|
||||
className="sidebar-main-menu__list"
|
||||
|
@ -289,7 +289,9 @@ window.comments = (() => {
|
||||
.forEach(initAddCommentButton);
|
||||
|
||||
// Attach the commenting app to the tab navigation, if it exists
|
||||
const tabNavElement = formElement.querySelector('[data-tab-nav]');
|
||||
const tabNavElement = formElement.querySelector(
|
||||
'[data-tabs] [role="tablist"]',
|
||||
);
|
||||
if (tabNavElement) {
|
||||
commentApp.setCurrentTab(tabNavElement.dataset.currentTab);
|
||||
tabNavElement.addEventListener('switch', (e) => {
|
||||
|
@ -11,6 +11,7 @@ function addMessage(status, text) {
|
||||
clearTimeout(addMsgTimeout);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
window.addMessage = addMessage;
|
||||
|
||||
function escapeHtml(text) {
|
||||
@ -24,6 +25,7 @@ function escapeHtml(text) {
|
||||
|
||||
return text.replace(/[&<>"']/g, (char) => map[char]);
|
||||
}
|
||||
|
||||
window.escapeHtml = escapeHtml;
|
||||
|
||||
function initTagField(id, autocompleteUrl, options) {
|
||||
@ -45,6 +47,7 @@ function initTagField(id, autocompleteUrl, options) {
|
||||
|
||||
$('#' + id).tagit(finalOptions);
|
||||
}
|
||||
|
||||
window.initTagField = initTagField;
|
||||
|
||||
/*
|
||||
@ -218,6 +221,7 @@ function enableDirtyFormCheck(formSelector, options) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.enableDirtyFormCheck = enableDirtyFormCheck;
|
||||
|
||||
$(() => {
|
||||
@ -240,7 +244,7 @@ $(() => {
|
||||
});
|
||||
|
||||
/* Functions that need to run/rerun when active tabs are changed */
|
||||
$(document).on('shown.bs.tab', () => {
|
||||
document.addEventListener('tab-changed', () => {
|
||||
// Resize autosize textareas
|
||||
// eslint-disable-next-line func-names
|
||||
$('textarea[data-autosize-on]').each(function () {
|
||||
@ -249,42 +253,6 @@ $(() => {
|
||||
});
|
||||
});
|
||||
|
||||
/* tabs */
|
||||
const showTab = (tabButtonElem) => {
|
||||
$(tabButtonElem).tab('show');
|
||||
|
||||
// Update data-current-tab attribute on the [data-tab-nav] element
|
||||
const tabNavElem = tabButtonElem.closest('[data-tab-nav]');
|
||||
tabNavElem.dataset.currentTab = tabButtonElem.dataset.tab;
|
||||
|
||||
// Trigger switch event
|
||||
tabNavElem.dispatchEvent(
|
||||
new CustomEvent('switch', { detail: { tab: tabButtonElem.dataset.tab } }),
|
||||
);
|
||||
};
|
||||
|
||||
if (window.location.hash) {
|
||||
/* look for a tab matching the URL hash and activate it if found */
|
||||
const cleanedHash = window.location.hash.replace(/[^\w\-#]/g, '');
|
||||
const tab = document.querySelector(
|
||||
'a[href="' + cleanedHash + '"][data-tab]',
|
||||
);
|
||||
if (tab) showTab(tab);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
$(document).on('click', '[data-tab-nav] a', function (e) {
|
||||
e.preventDefault();
|
||||
showTab(this);
|
||||
window.history.replaceState(null, null, $(this).attr('href'));
|
||||
});
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
$(document).on('click', '.tab-toggle', function (e) {
|
||||
e.preventDefault();
|
||||
$('[data-tab-nav] a[href="' + $(this).attr('href') + '"]').trigger('click');
|
||||
});
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
$('.dropdown').each(function () {
|
||||
const $dropdown = $(this);
|
||||
|
@ -255,9 +255,11 @@ function initErrorDetection() {
|
||||
// now identify them on each tab
|
||||
// eslint-disable-next-line guard-for-in
|
||||
for (const index in errorSections) {
|
||||
$('[data-tab-nav] a[href="#' + index + '"]')
|
||||
.addClass('errors')
|
||||
.attr('data-count', errorSections[index]);
|
||||
$('[data-tabs] a[href="#' + index + '"]')
|
||||
.find('.w-tabs__errors')
|
||||
.addClass('w-tabs__errors--active')
|
||||
.find('.w-tabs__errors-count')
|
||||
.text(errorSections[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import $ from 'jquery';
|
||||
import { initTabs } from '../../includes/tabs';
|
||||
|
||||
const ajaxifyTaskCreateTab = (modal, jsonData) => {
|
||||
$(
|
||||
'#new a.task-type-choice, #new a.choose-different-task-type',
|
||||
'#tab-new a.task-type-choice, #tab-new a.choose-different-task-type',
|
||||
modal.body,
|
||||
).on('click', function onClickNew() {
|
||||
modal.loadUrl(this.href);
|
||||
@ -28,7 +29,7 @@ const ajaxifyTaskCreateTab = (modal, jsonData) => {
|
||||
errorThrown +
|
||||
' - ' +
|
||||
response.status;
|
||||
$('#new', modal.body).append(
|
||||
$('#tab-new', modal.body).append(
|
||||
'<div class="help-block help-critical">' +
|
||||
'<strong>' +
|
||||
jsonData.error_label +
|
||||
@ -59,12 +60,6 @@ const TASK_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
fetchResults(this.href);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('a.create-one-now').on('click', (e) => {
|
||||
// Select upload form tab
|
||||
$('a[href="#new"]').tab('show');
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
const searchForm = $('form.task-search', modal.body);
|
||||
@ -118,13 +113,16 @@ const TASK_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
const wait = setTimeout(search, 50);
|
||||
$(this).data('timer', wait);
|
||||
});
|
||||
|
||||
// Reinitialize tabs to hook up tab event listeners in the modal
|
||||
initTabs();
|
||||
},
|
||||
task_chosen(modal, jsonData) {
|
||||
modal.respond('taskChosen', jsonData.result);
|
||||
modal.close();
|
||||
},
|
||||
reshow_create_tab(modal, jsonData) {
|
||||
$('#new', modal.body).html(jsonData.htmlFragment);
|
||||
$('#tab-new', modal.body).html(jsonData.htmlFragment);
|
||||
ajaxifyTaskCreateTab(modal, jsonData);
|
||||
},
|
||||
};
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Icon, Portal, initUpgradeNotification, initSkipLink } from '../..';
|
||||
import { initModernDropdown, initTooltips } from '../../includes/initTooltips';
|
||||
import { initTabs } from '../../includes/tabs';
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// Run react-axe in development only, so it does not affect performance
|
||||
@ -24,5 +25,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
initUpgradeNotification();
|
||||
initTooltips();
|
||||
initModernDropdown();
|
||||
initTabs();
|
||||
initSkipLink();
|
||||
});
|
||||
|
@ -1,3 +1,6 @@
|
||||
import $ from 'jquery';
|
||||
import { initTabs } from '../../includes/tabs';
|
||||
|
||||
function ajaxifyDocumentUploadForm(modal) {
|
||||
$('form.document-upload', modal.body).on('submit', function () {
|
||||
var formdata = new FormData(this);
|
||||
@ -17,7 +20,7 @@ function ajaxifyDocumentUploadForm(modal) {
|
||||
errorThrown +
|
||||
' - ' +
|
||||
response.status;
|
||||
$('#upload', modal.body).append(
|
||||
$('#tab-upload', modal.body).append(
|
||||
'<div class="help-block help-critical">' +
|
||||
'<strong>' +
|
||||
jsonData.error_label +
|
||||
@ -67,7 +70,7 @@ function ajaxifyDocumentUploadForm(modal) {
|
||||
});
|
||||
}
|
||||
|
||||
DOCUMENT_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
window.DOCUMENT_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
chooser: function (modal, jsonData) {
|
||||
function ajaxifyLinks(context) {
|
||||
$('a.document-choice', context).on('click', function () {
|
||||
@ -87,8 +90,6 @@ DOCUMENT_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
$('#id_document-chooser-upload-collection').val(collectionId);
|
||||
}
|
||||
|
||||
// Select upload form tab
|
||||
$('a[href="#upload"]').tab('show');
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
@ -134,13 +135,17 @@ DOCUMENT_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
});
|
||||
|
||||
$('#collection_chooser_collection_id').on('change', search);
|
||||
|
||||
// Reinitialize tabs to hook up tab event listeners in the modal
|
||||
initTabs();
|
||||
},
|
||||
document_chosen: function (modal, jsonData) {
|
||||
modal.respond('documentChosen', jsonData.result);
|
||||
modal.close();
|
||||
},
|
||||
reshow_upload_form: function (modal, jsonData) {
|
||||
$('#upload', modal.body).html(jsonData.htmlFragment);
|
||||
$('#tab-upload', modal.body).replaceWith(jsonData.htmlFragment);
|
||||
initTabs();
|
||||
ajaxifyDocumentUploadForm(modal);
|
||||
},
|
||||
};
|
@ -1,3 +1,6 @@
|
||||
import $ from 'jquery';
|
||||
import { initTabs } from '../../includes/tabs';
|
||||
|
||||
function ajaxifyImageUploadForm(modal) {
|
||||
$('form.image-upload', modal.body).on('submit', function () {
|
||||
var formdata = new FormData(this);
|
||||
@ -29,7 +32,7 @@ function ajaxifyImageUploadForm(modal) {
|
||||
errorThrown +
|
||||
' - ' +
|
||||
response.status;
|
||||
$('#upload').append(
|
||||
$('#tab-upload').append(
|
||||
'<div class="help-block help-critical">' +
|
||||
'<strong>' +
|
||||
jsonData.error_label +
|
||||
@ -80,7 +83,7 @@ function ajaxifyImageUploadForm(modal) {
|
||||
});
|
||||
}
|
||||
|
||||
IMAGE_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
window.IMAGE_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
chooser: function (modal, jsonData) {
|
||||
var searchForm = $('form.image-search', modal.body);
|
||||
var searchUrl = searchForm.attr('action');
|
||||
@ -143,13 +146,17 @@ IMAGE_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// Reinitialize tabs to hook up tab event listeners in the modal
|
||||
initTabs();
|
||||
},
|
||||
image_chosen: function (modal, jsonData) {
|
||||
modal.respond('imageChosen', jsonData.result);
|
||||
modal.close();
|
||||
},
|
||||
reshow_upload_form: function (modal, jsonData) {
|
||||
$('#upload', modal.body).replaceWith(jsonData.htmlFragment);
|
||||
$('#tab-upload', modal.body).replaceWith(jsonData.htmlFragment);
|
||||
initTabs();
|
||||
ajaxifyImageUploadForm(modal);
|
||||
},
|
||||
select_format: function (modal) {
|
@ -95,4 +95,5 @@ function createImageChooser(id) {
|
||||
|
||||
return chooser;
|
||||
}
|
||||
|
||||
window.createImageChooser = createImageChooser;
|
||||
|
@ -1,5 +1,8 @@
|
||||
export default function initCollapsibleBreadcrumbs() {
|
||||
const breadcrumbsContainer = document.querySelector('[data-breadcrumb-next]');
|
||||
if (!breadcrumbsContainer) {
|
||||
return;
|
||||
}
|
||||
const breadcrumbsToggle = breadcrumbsContainer.querySelector(
|
||||
'[data-toggle-breadcrumbs]',
|
||||
);
|
||||
|
327
client/src/includes/tabs.js
Normal file
327
client/src/includes/tabs.js
Normal file
@ -0,0 +1,327 @@
|
||||
/**
|
||||
* All tabs and tab content must be nested in an element with the data-tab attribute
|
||||
* All tab buttons need the role="tab" attr and an href with the tab content ID
|
||||
* Tab contents need to have the role="tabpanel" attribute and and ID attribute that matches the href of the tab link.
|
||||
* Tab buttons should also be wrapped in an element with the role="tablist" attribute
|
||||
*/
|
||||
class Tabs {
|
||||
constructor(node) {
|
||||
this.tabContainer = node;
|
||||
this.tabButtons = this.tabContainer.querySelectorAll('[role="tab"]');
|
||||
this.tabList = this.tabContainer.querySelector('[role="tablist"]');
|
||||
this.tabPanels = this.tabContainer.querySelectorAll('[role="tabpanel"]');
|
||||
this.keydownEventListener = this.keydownEventListener.bind(this);
|
||||
|
||||
// Tab Options - Add these data attributes along side the data-tabs attribute
|
||||
// Use this to enable fade-in animations on tab select
|
||||
this.animate = this.tabContainer.hasAttribute('data-tabs-animate');
|
||||
// Disable url hash from appearing on tab select (normally used in modals)
|
||||
this.disableURL = this.tabContainer.hasAttribute('data-tabs-disable-url');
|
||||
|
||||
this.state = {
|
||||
// Tab Settings
|
||||
activeTabID: '',
|
||||
transition: 150,
|
||||
initialPageLoad: true,
|
||||
// CSS Classes
|
||||
css: {
|
||||
animate: 'animate-in',
|
||||
},
|
||||
// Keyboard Keys
|
||||
keys: {
|
||||
end: 'End',
|
||||
home: 'Home',
|
||||
left: 'ArrowLeft',
|
||||
up: 'ArrowUp',
|
||||
right: 'ArrowRight',
|
||||
down: 'ArrowDown',
|
||||
},
|
||||
direction: {
|
||||
ArrowLeft: -1,
|
||||
ArrowRight: 1,
|
||||
},
|
||||
};
|
||||
|
||||
this.onComponentLoaded();
|
||||
}
|
||||
|
||||
onComponentLoaded() {
|
||||
this.bindEvents();
|
||||
|
||||
// Set active tab from url or make first tab active
|
||||
if (this.tabButtons) {
|
||||
// Set each button's aria-controls attribute and select tab if aria-selected has already been set on the element
|
||||
this.tabButtons.forEach((button) => {
|
||||
button.setAttribute(
|
||||
'aria-controls',
|
||||
button.getAttribute('href').replace('#', ''),
|
||||
);
|
||||
});
|
||||
|
||||
// Check for active items set by the template
|
||||
const tabActive = [...this.tabButtons].find(
|
||||
(button) => button.getAttribute('aria-selected') === 'true',
|
||||
);
|
||||
|
||||
if (window.location.hash && !this.disableURL) {
|
||||
this.selectTabByURLHash();
|
||||
} else if (tabActive) {
|
||||
// If a tab isn't hidden for some reason hide it
|
||||
this.tabPanels.forEach((tab) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
tab.hidden = true;
|
||||
});
|
||||
// Show aria-selected tab
|
||||
this.selectTab(tabActive);
|
||||
} else {
|
||||
this.selectFirstTab();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string}newTabId
|
||||
*/
|
||||
unSelectActiveTab(newTabId) {
|
||||
// IF new tab ID is the current then don't transition out
|
||||
if (newTabId === this.state.activeTabID || !this.state.activeTabID) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Tab Content to deactivate
|
||||
const tabContent = this.tabContainer.querySelector(
|
||||
`#${this.state.activeTabID}`,
|
||||
);
|
||||
|
||||
if (!tabContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.animate) {
|
||||
this.animateOut(tabContent);
|
||||
} else {
|
||||
tabContent.hidden = true;
|
||||
}
|
||||
|
||||
const tab = this.tabContainer.querySelector(
|
||||
`a[href='#${this.state.activeTabID}']`,
|
||||
);
|
||||
|
||||
tab.setAttribute('aria-selected', 'false');
|
||||
tab.setAttribute('tabindex', '-1');
|
||||
}
|
||||
|
||||
selectTab(tab) {
|
||||
if (!tab) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tabContentId = tab.getAttribute('aria-controls');
|
||||
|
||||
// Unselect currently active tab
|
||||
if (tabContentId) {
|
||||
this.unSelectActiveTab(tabContentId);
|
||||
}
|
||||
|
||||
this.state.activeTabID = tabContentId;
|
||||
|
||||
const linkedTab = this.tabContainer.querySelector(
|
||||
`a[href="${tab.getAttribute('href')}"][role="tab"]`,
|
||||
);
|
||||
|
||||
// If an external button was used to trigger the tab, make sure active tab is marked active
|
||||
if (linkedTab) {
|
||||
linkedTab.setAttribute('aria-selected', 'true');
|
||||
linkedTab.removeAttribute('tabindex');
|
||||
}
|
||||
|
||||
tab.setAttribute('aria-selected', 'true');
|
||||
tab.removeAttribute('tabindex');
|
||||
|
||||
const tabContent = this.tabContainer.querySelector(`#${tabContentId}`);
|
||||
if (!tabContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.animate) {
|
||||
this.animateIn(tabContent);
|
||||
} else {
|
||||
tabContent.hidden = false;
|
||||
}
|
||||
|
||||
if (this.state.initialPageLoad) {
|
||||
// On first load set the scroll to top to avoid scrolling to active section and header covering up tabs
|
||||
setTimeout(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, this.state.transition * 2);
|
||||
}
|
||||
|
||||
// Dispatch tab selected event for the rest of the admin to hook into if needed
|
||||
// Trigger tab specific switch event
|
||||
this.tabList.dispatchEvent(
|
||||
new CustomEvent('switch', { detail: { tab: tab.dataset.tab } }),
|
||||
);
|
||||
// Dispatch tab-changed event on the document
|
||||
document.dispatchEvent(new CustomEvent('tab-changed'));
|
||||
|
||||
// Set URL hash and browser history
|
||||
if (!this.disableURL) {
|
||||
this.setURLHash(tabContentId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade Up and In animation
|
||||
* @param tabContent{HTMLElement}
|
||||
*/
|
||||
animateIn(tabContent) {
|
||||
setTimeout(() => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
tabContent.hidden = false;
|
||||
// Wait for hidden attribute to be applied then fade in
|
||||
setTimeout(() => {
|
||||
tabContent.classList.add(this.state.css.animate);
|
||||
}, this.state.transition);
|
||||
}, this.state.transition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade Down and Out by removing css class
|
||||
* @param tabContent{HTMLElement}
|
||||
*/
|
||||
animateOut(tabContent) {
|
||||
// Wait element to transition out and then hide with hidden
|
||||
tabContent.classList.remove(this.state.css.animate);
|
||||
setTimeout(() => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
tabContent.hidden = true;
|
||||
}, this.state.transition);
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
if (!this.tabButtons) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.tabButtons.forEach((tab, index) => {
|
||||
tab.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.selectTab(tab);
|
||||
});
|
||||
tab.addEventListener('focusin', () => {
|
||||
this.selectTab(tab);
|
||||
});
|
||||
tab.addEventListener('keydown', this.keydownEventListener);
|
||||
// Set index of tab used in keyboard controls
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
tab.index = index;
|
||||
});
|
||||
|
||||
// Select previous or next tab using history
|
||||
window.addEventListener('popstate', (e) => {
|
||||
if (e.state && e.state.tabContent) {
|
||||
const tab = this.tabContainer.querySelector(
|
||||
`a[href="#${e.state.tabContent}"][role="tab"]`,
|
||||
);
|
||||
if (tab) {
|
||||
this.selectTab(tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle keydown on tabs
|
||||
* @param {Event}event
|
||||
*/
|
||||
keydownEventListener(event) {
|
||||
const keyPressed = event.key;
|
||||
const { keys } = this.state;
|
||||
|
||||
switch (keyPressed) {
|
||||
case keys.left:
|
||||
case keys.right:
|
||||
this.switchTabOnArrowPress(event);
|
||||
break;
|
||||
case keys.end:
|
||||
event.preventDefault();
|
||||
this.focusLastTab();
|
||||
break;
|
||||
case keys.home:
|
||||
event.preventDefault();
|
||||
this.focusFirstTab();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
selectTabByURLHash() {
|
||||
if (window.location.hash) {
|
||||
const cleanedHash = window.location.hash.replace(/[^\w\-#]/g, '');
|
||||
const tab = this.tabContainer.querySelector(
|
||||
`a[href="${cleanedHash}"][role="tab"]`,
|
||||
);
|
||||
if (tab) {
|
||||
this.selectTab(tab);
|
||||
} else {
|
||||
// The hash doesn't match a tab on the page then select first tab
|
||||
this.selectFirstTab();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set url to have tab an tab hash at the end
|
||||
*/
|
||||
setURLHash(tabId) {
|
||||
if (
|
||||
!this.state.initialPageLoad &&
|
||||
(!window.history.state || window.history.state.tabContent !== tabId)
|
||||
) {
|
||||
// Add a new history item to the stack
|
||||
window.history.pushState({ tabContent: tabId }, null, `#${tabId}`);
|
||||
}
|
||||
this.state.initialPageLoad = false;
|
||||
}
|
||||
|
||||
// Either focus the next, previous, first, or last tab depending on key pressed
|
||||
switchTabOnArrowPress(event) {
|
||||
const pressed = event.key;
|
||||
const { direction } = this.state;
|
||||
const { keys } = this.state;
|
||||
const tabs = this.tabButtons;
|
||||
|
||||
if (direction[pressed]) {
|
||||
const target = event.target;
|
||||
if (target.index !== undefined) {
|
||||
if (tabs[target.index + direction[pressed]]) {
|
||||
tabs[target.index + direction[pressed]].focus();
|
||||
} else if (pressed === keys.left) {
|
||||
this.focusLastTab();
|
||||
} else if (pressed === keys.right) {
|
||||
this.focusFirstTab();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
focusFirstTab() {
|
||||
this.tabButtons[0].focus();
|
||||
}
|
||||
|
||||
focusLastTab() {
|
||||
this.tabButtons[this.tabButtons.length - 1].focus();
|
||||
}
|
||||
|
||||
selectFirstTab() {
|
||||
this.selectTab(this.tabButtons[0]);
|
||||
this.state.activeTabID = this.tabButtons[0].getAttribute('aria-controls');
|
||||
}
|
||||
}
|
||||
|
||||
export default Tabs;
|
||||
|
||||
export const initTabs = (tabs = document.querySelectorAll('[data-tabs]')) => {
|
||||
tabs.forEach((tabSet) => new Tabs(tabSet));
|
||||
};
|
33
client/src/plugins/scrollbarThin.js
Normal file
33
client/src/plugins/scrollbarThin.js
Normal file
@ -0,0 +1,33 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const plugin = require('tailwindcss/plugin');
|
||||
|
||||
module.exports = plugin(({ addComponents, theme }) => {
|
||||
addComponents({
|
||||
// Scrollbar styling for firefox
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color
|
||||
'.scrollbar-thin': {
|
||||
'scrollbarColor': `${theme('colors.grey.100')} ${theme(
|
||||
'colors.white.DEFAULT',
|
||||
)}`,
|
||||
'scrollbarWidth': 'thin',
|
||||
|
||||
// Custom scrollbar styling for Safari & Chrome Windows / Mac / Android.
|
||||
'&::-webkit-scrollbar': {
|
||||
width: '5px',
|
||||
height: '5px',
|
||||
},
|
||||
'&::-webkit-scrollbar-button': {
|
||||
// Hide the scrollbar arrows on windows
|
||||
display: 'none',
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
// Hide the scrollbar arrows on windows
|
||||
backgroundColor: theme('colors.grey.200'),
|
||||
borderRadius: theme('borderRadius.sm'),
|
||||
},
|
||||
'&::-webkit-scrollbar-track': {
|
||||
background: theme('colors.transparent'),
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
@ -1,6 +1,5 @@
|
||||
const plugin = require('tailwindcss/plugin');
|
||||
const vanillaRTL = require('tailwindcss-vanilla-rtl');
|
||||
|
||||
/**
|
||||
* Design Tokens
|
||||
*/
|
||||
@ -24,6 +23,7 @@ const { spacing } = require('./src/tokens/spacing');
|
||||
* Plugins
|
||||
*/
|
||||
const typeScale = require('./src/tokens/typeScale');
|
||||
const scrollbarThin = require('./src/plugins/scrollbarThin');
|
||||
|
||||
/**
|
||||
* Functions
|
||||
@ -81,6 +81,7 @@ module.exports = {
|
||||
plugins: [
|
||||
typeScale,
|
||||
vanillaRTL,
|
||||
scrollbarThin,
|
||||
/**
|
||||
* forced-colors media query for Windows High-Contrast mode support
|
||||
* See:
|
||||
|
@ -56,8 +56,16 @@ module.exports = function exports(env, argv) {
|
||||
'workflow-status',
|
||||
'bulk-actions',
|
||||
],
|
||||
'images': ['image-chooser', 'image-chooser-telepath'],
|
||||
'documents': ['document-chooser', 'document-chooser-telepath'],
|
||||
'images': [
|
||||
'image-chooser',
|
||||
'image-chooser-modal',
|
||||
'image-chooser-telepath',
|
||||
],
|
||||
'documents': [
|
||||
'document-chooser',
|
||||
'document-chooser-modal',
|
||||
'document-chooser-telepath',
|
||||
],
|
||||
'snippets': ['snippet-chooser', 'snippet-chooser-telepath'],
|
||||
'contrib/table_block': ['table'],
|
||||
'contrib/typed_table_block': ['typed_table_block'],
|
||||
|
@ -19,6 +19,7 @@ Here are other changes related to the redesign:
|
||||
* Fully remove the legacy sidebar, with slim sidebar replacing it for all users (Thibaud Colas)
|
||||
* Add support for adding custom attributes for link menu items in the slim sidebar (Thibaud Colas)
|
||||
* Implement new slim page editor header with breadcrumb (Steven Steinwand, Karl Hobley)
|
||||
* Implement new tabs design across the admin interface (Steven Steinwand)
|
||||
|
||||
### Removal of special-purpose field panel types
|
||||
|
||||
@ -78,6 +79,7 @@ class LandingPage(Page):
|
||||
* Add the ability for choices to be separated by new lines instead of just commas within the form builder, commas will still be supported if used (Abdulmajeed Isa)
|
||||
* Add internationalisation UI to modeladmin (Andrés Martano)
|
||||
* Support chunking in `PageQuerySet.specific()` to reduce memory consumption (Andy Babic)
|
||||
* Fix: Implement ARIA tabs markup and keyboards interactions for admin tabs (Steven Steinwand)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
@ -126,7 +128,7 @@ wagtail updatemodulepaths # actually update the files
|
||||
### Removed warning in Internet Explorer (IE11)
|
||||
|
||||
* IE11 support was officially dropped in Wagtail 2.15, as of this release there will no longer be a warning shown to users of this browser.
|
||||
* Wagtail is fully compatible with Microsoft Edge, Microsoft’s replacement for Internet Explorer. You may consider using its `IE mode <https://docs.microsoft.com/en-us/deployedge/edge-ie-mode>`_ to keep access to IE11-only sites, while other sites and apps like Wagtail can leverage modern browser capabilities.
|
||||
* Wagtail is fully compatible with Microsoft Edge, Microsoft’s replacement for Internet Explorer. You may consider using its [IE mode](https://docs.microsoft.com/en-us/deployedge/edge-ie-mode) to keep access to IE11-only sites, while other sites and apps like Wagtail can leverage modern browser capabilities.
|
||||
|
||||
### Replaced `content_json` `TextField` with `content` `JSONField` in `PageRevision`
|
||||
|
||||
@ -218,4 +220,3 @@ After setting the keyword argument, make sure to generate and run the migrations
|
||||
### Removed support for Jinja2 2.x
|
||||
|
||||
Jinja2 2.x is no longer supported as of this release; if you are using Jinja2 templating on your project, please upgrade to Jinja2 3.0 or above.
|
||||
|
||||
|
@ -1,138 +0,0 @@
|
||||
/* ========================================================================
|
||||
* Bootstrap: tab.js v3.0.0
|
||||
* http://twbs.github.com/bootstrap/javascript.html#tabs
|
||||
* ========================================================================
|
||||
* Copyright 2012 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
+function ($) { "use strict";
|
||||
|
||||
// TAB CLASS DEFINITION
|
||||
// ====================
|
||||
|
||||
var Tab = function (element) {
|
||||
this.element = $(element)
|
||||
}
|
||||
|
||||
Tab.prototype.show = function () {
|
||||
var $this = this.element
|
||||
var $ul = $this.closest('ul:not(.dropdown-menu)')
|
||||
var selector = $this.attr('data-target')
|
||||
|
||||
if (!selector) {
|
||||
selector = $this.attr('href')
|
||||
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
|
||||
}
|
||||
|
||||
if ($this.parent('li').hasClass('active')) return
|
||||
|
||||
var previous = $ul.find('.active:last a')[0]
|
||||
var e = $.Event('show.bs.tab', {
|
||||
relatedTarget: previous
|
||||
})
|
||||
|
||||
$this.trigger(e)
|
||||
|
||||
if (e.isDefaultPrevented()) return
|
||||
|
||||
var $target = $(selector)
|
||||
|
||||
this.activate($this, $this.parent('li'), $ul)
|
||||
this.activate($this, $target, $target.parent(), function () {
|
||||
$this.trigger({
|
||||
type: 'shown.bs.tab'
|
||||
, relatedTarget: previous
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Tab.prototype.activate = function (trigger, element, container, callback) {
|
||||
var $active = container.find('> .active')
|
||||
var transition = callback
|
||||
&& $.support.transition
|
||||
&& $active.hasClass('fade')
|
||||
|
||||
function next() {
|
||||
element.parent().find('.active').removeClass('active');
|
||||
$active
|
||||
.removeClass('active')
|
||||
.find('> .dropdown-menu > .active')
|
||||
.removeClass('active')
|
||||
|
||||
|
||||
trigger.addClass('active');
|
||||
element.addClass('active');
|
||||
|
||||
if (transition) {
|
||||
element[0].offsetWidth // reflow for transition
|
||||
element.addClass('in')
|
||||
} else {
|
||||
element.removeClass('fade')
|
||||
}
|
||||
|
||||
if (element.parent('.dropdown-menu')) {
|
||||
element.closest('li.dropdown').addClass('active')
|
||||
}
|
||||
|
||||
callback && callback()
|
||||
}
|
||||
|
||||
transition ?
|
||||
$active
|
||||
.one($.support.transition.end, next)
|
||||
.emulateTransitionEnd(150) :
|
||||
next()
|
||||
|
||||
$active.removeClass('in')
|
||||
}
|
||||
|
||||
|
||||
// TAB PLUGIN DEFINITION
|
||||
// =====================
|
||||
|
||||
var old = $.fn.tab
|
||||
|
||||
$.fn.tab = function ( option ) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('bs.tab')
|
||||
|
||||
if (!data) $this.data('bs.tab', (data = new Tab(this)))
|
||||
if (typeof option == 'string') data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.tab.Constructor = Tab
|
||||
|
||||
|
||||
// TAB NO CONFLICT
|
||||
// ===============
|
||||
|
||||
$.fn.tab.noConflict = function () {
|
||||
$.fn.tab = old
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
// TAB DATA-API
|
||||
// ============
|
||||
|
||||
$(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
|
||||
e.preventDefault()
|
||||
$(this).tab('show')
|
||||
})
|
||||
|
||||
}(window.jQuery);
|
@ -4,69 +4,87 @@
|
||||
{% block titletag %}{% trans "Account" %}{% endblock %}
|
||||
{% block content %}
|
||||
{% trans "Account" as account_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=account_str merged=1 tabbed=1 %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=account_str merged=1 %}
|
||||
|
||||
<ul class="tab-nav merged" data-tab-nav>
|
||||
{% for tab in panels_by_tab.keys %}
|
||||
<li{% if forloop.first %} class="active"{% endif %}><a href="#{{ tab.name }}">{{ tab.title }}</a></li>
|
||||
{% endfor %}
|
||||
<div class="w-tabs" data-tabs data-tabs-animate>
|
||||
<div class="w-tabs__wrapper">
|
||||
<div role="tablist" class="w-tabs__list nice-padding">
|
||||
{% for tab in panels_by_tab.keys %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id=tab.name title=tab.title %}
|
||||
{% endfor %}
|
||||
|
||||
{% if menu_items %}
|
||||
<li><a href="#actions">{% trans "More actions" %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% if menu_items %}
|
||||
{% trans 'More actions' as menu_items_title %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='actions' title=menu_items_title %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="{% url 'wagtailadmin_account' %}" method="post" enctype="multipart/form-data" novalidate>
|
||||
<div class="tab-content">
|
||||
{% csrf_token %}
|
||||
<form action="{% url 'wagtailadmin_account' %}" method="post" enctype="multipart/form-data" novalidate>
|
||||
<div class="tab-content">
|
||||
{% csrf_token %}
|
||||
|
||||
{% for tab, panels in panels_by_tab.items %}
|
||||
<section id="{{ tab.name }}"{% if forloop.first %} class="active"{% endif %}>
|
||||
<ul class="objects">
|
||||
{% for panel in panels %}
|
||||
<li class="object">
|
||||
<div class="title-wrapper">
|
||||
<label>{{ panel.title }}</label>
|
||||
</div>
|
||||
<div class="object-layout">
|
||||
<div class="object-layout_big-part">
|
||||
<div class="top-padding">
|
||||
{{ panel.render }}
|
||||
{% for tab, panels in panels_by_tab.items %}
|
||||
<section
|
||||
id="tab-{{ tab.name|cautious_slugify }}"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="tab-label-{{ tab.name|cautious_slugify }}"
|
||||
>
|
||||
<ul class="objects">
|
||||
{% for panel in panels %}
|
||||
<li class="object">
|
||||
<div class="title-wrapper">
|
||||
<label>{{ panel.title }}</label>
|
||||
</div>
|
||||
<div class="object-layout">
|
||||
<div class="object-layout_big-part">
|
||||
<div class="top-padding">
|
||||
{{ panel.render }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<div class="top-padding nice-padding">
|
||||
<button type="submit" class="button">{% trans 'Save account details' %}</button>
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
<div class="top-padding nice-padding">
|
||||
<button type="submit" class="button">{% trans 'Save account details' %}</button>
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
||||
{% if menu_items %}
|
||||
<section
|
||||
id="tab-actions"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="tab-label-actions"
|
||||
>
|
||||
<ul class="listing">
|
||||
{% for item in menu_items %}
|
||||
<li class="row row-flush">
|
||||
<div class="col6">
|
||||
<a href="{{ item.url }}" class="button button-primary">{{ item.label }}</a>
|
||||
</div>
|
||||
<small class="col6">{{ item.help_text }}</small>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if menu_items %}
|
||||
<section id="actions" class="nice-padding">
|
||||
<ul class="listing">
|
||||
{% for item in menu_items %}
|
||||
<li class="row row-flush">
|
||||
<div class="col6">
|
||||
<a href="{{ item.url }}" class="button button-primary">{{ item.label }}</a>
|
||||
</div>
|
||||
<small class="col6">{{ item.help_text }}</small>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
{{ block.super }}
|
||||
{% include "wagtailadmin/pages/_editor_css.html" %}
|
||||
<link rel="stylesheet" href="{% versioned_static 'wagtailadmin/css/layouts/account.css' %}" type="text/css" />
|
||||
<link rel="stylesheet" href="{% versioned_static 'wagtailadmin/css/layouts/account.css' %}" type="text/css"/>
|
||||
{{ media.css }}
|
||||
{% endblock %}
|
||||
{% block extra_js %}
|
||||
|
@ -1,31 +1,42 @@
|
||||
{% load wagtailadmin_tags i18n %}
|
||||
<div class="tab-nav merged">
|
||||
<ul data-tab-nav role="tablist" data-current-tab="{{ self.children.0.heading|cautious_slugify }}">
|
||||
{% for child in self.children %}
|
||||
<li class="{{ child.classes|join:" " }} {% if forloop.first %}active{% endif %}" role="tab" aria-controls="tab-{{ child.heading|cautious_slugify }}">
|
||||
<a href="#tab-{{ child.heading|cautious_slugify }}" class="{% if forloop.first %}active{% endif %}" data-tab="{{ child.heading|cautious_slugify }}">{{ child.heading }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if self.form.show_comments_toggle %}
|
||||
<div class="right wide">
|
||||
<div class="comments-controls" hidden data-comment-notifications>
|
||||
<div class="comment-notifications-toggle">
|
||||
<label class="switch switch--teal-background">
|
||||
{% trans "Comment notifications" %}
|
||||
{{ self.form.comment_notifications }}
|
||||
<span class="switch__toggle"></span>
|
||||
</label>
|
||||
|
||||
<div class="w-tabs" data-tabs data-tabs-animate>
|
||||
<div class="w-tabs__wrapper">
|
||||
<div role="tablist" class="w-tabs__list w-px-5 sm:w-px-[4.5rem]">
|
||||
{% for child in self.children %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id=child.heading title=child.heading classes=child.classes|join:" " %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template>
|
||||
{# TODO To be re-implemented for comments side panel #}
|
||||
{% if self.form.show_comments_toggle %}
|
||||
<div class="right wide">
|
||||
<div class="comments-controls" hidden data-comment-notifications>
|
||||
<div class="comment-notifications-toggle">
|
||||
<label class="switch switch--teal-background">
|
||||
{% trans "Comment notifications" %}
|
||||
{{ self.form.comment_notifications }}
|
||||
<span class="switch__toggle"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</template>
|
||||
|
||||
<div class="tab-content">
|
||||
{% for child in self.children %}
|
||||
<section id="tab-{{ child.heading|cautious_slugify }}" class="{{ child.classes|join:" " }} {% if forloop.first %}active{% endif %}" role="tabpanel" aria-labelledby="tab-label-{{ child.heading|cautious_slugify }}" data-tab="{{ child.heading|cautious_slugify }}">
|
||||
{{ child.render_as_object }}
|
||||
</section>
|
||||
{% endfor %}
|
||||
<div class="tab-content">
|
||||
{% for child in self.children %}
|
||||
<section
|
||||
id="tab-{{ child.heading|cautious_slugify }}"
|
||||
class="w-tabs__panel {{ child.classes|join:" " }}"
|
||||
role="tabpanel"
|
||||
aria-labelledby="tab-label-{{ child.heading|cautious_slugify }}"
|
||||
hidden
|
||||
>
|
||||
{{ child.render_as_object }}
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -8,7 +8,7 @@
|
||||
{% with breadcrumb_link_classes='w-text-grey-600 w-text-14 w-no-underline w-outline-offset-inside hover:w-underline hover:w-text-primary' breadcrumb_item_classes='w-flex w-items-center w-overflow-hidden w-transition w-duration-300 w-whitespace-nowrap w-flex-shrink-0' icon_classes='w-w-4 w-h-4 w-mr-3' %}
|
||||
{# Breadcrumbs are visible on mobile by default but hidden on desktop #}
|
||||
|
||||
<div class="w-flex w-flex-row w-items-center w-overflow-x-auto w-overflow-y-hidden u-scrollbar-thin" data-breadcrumb-next>
|
||||
<div class="w-flex w-flex-row w-items-center w-overflow-x-auto w-overflow-y-hidden w-scrollbar-thin" data-breadcrumb-next>
|
||||
<button
|
||||
type="button"
|
||||
data-toggle-breadcrumbs
|
||||
|
@ -8,16 +8,15 @@
|
||||
- `search_url` - if present, display a search box. This is a URL route name (taking no parameters) to be used as the action for that search box
|
||||
- `query_parameters` - a query string (without the '?') to be placed after the search URL
|
||||
- `icon` - name of an icon to place against the title
|
||||
- `tabbed` - if true, add the classname 'tab-merged'
|
||||
- `merged` - if true, add the classname 'merged'
|
||||
- `action_url` - if present, display an 'action' button. This is the URL to be used as the link URL for the button
|
||||
- `action_text` - text for the 'action' button
|
||||
- `action_icon` - icon for the 'action' button, default is 'icon-plus'
|
||||
|
||||
{% endcomment %}
|
||||
<header class="{% if merged %}merged{% endif %} {% if tabbed %}tab-merged{% endif %} {% if search_form %}hasform{% endif %}">
|
||||
<header class="{% if merged %}merged{% endif %} {% if search_form %}hasform{% endif %}">
|
||||
{% block breadcrumb %}{% endblock %}
|
||||
<div class="row{% if not tabbed %} nice-padding{% endif %}">
|
||||
<div class="row nice-padding">
|
||||
<div class="left">
|
||||
<div class="col header-title">
|
||||
<h1>{% if icon %}{% icon name=icon class_name="header-title-icon" %}{% endif %}
|
||||
|
@ -0,0 +1,19 @@
|
||||
{% load wagtailadmin_tags i18n %}
|
||||
|
||||
{% comment %}
|
||||
Variables accepted by this template:
|
||||
|
||||
- `tab_id` - {string} A unique tab id
|
||||
- `title` - {string} Text that the tab button will display
|
||||
- `active` - {boolean?} Force this to be active
|
||||
- `classes` - {string?} Extra css classes to pass to this component
|
||||
- `errors_count` - {number?} Show above the tab for errors count
|
||||
{% endcomment %}
|
||||
|
||||
<a id="tab-label-{{ tab_id|cautious_slugify }}" href="#tab-{{ tab_id|cautious_slugify }}" class="w-tabs__tab {{ classes }}" role="tab" aria-selected="false" tabindex="-1">
|
||||
<div class="w-tabs__errors {% if errors_count %}w-tabs__errors--active{% endif %}">
|
||||
<span class="w-sr-only">{% trans 'Errors Count: ' %}</span>
|
||||
<span class="w-tabs__errors-count">{{ errors_count }}</span>
|
||||
</div>
|
||||
{{ title }}
|
||||
</a>
|
@ -1,21 +1,51 @@
|
||||
{% load i18n %}
|
||||
{% trans "Choose a task" as choose_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=choose_str tabbed=1 merged=1 icon="thumbtack" %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=choose_str merged=1 icon="thumbtack" %}
|
||||
|
||||
{% if can_create %}
|
||||
<ul class="tab-nav merged" data-tab-nav>
|
||||
<li class="active"><a href="#new">{% trans "New" %}</a></li>
|
||||
<li><a href="#existing">{% trans "Existing" %}</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
<div class="w-tabs" data-tabs data-tabs-disable-url>
|
||||
<div class="w-tabs__wrapper w-overflow-hidden">
|
||||
{# Using nice-padding and full width class until the modal header is restyled #}
|
||||
<div role="tablist" class="w-tabs__list w-w-full nice-padding">
|
||||
{% trans "New" as new_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='new' title=new_text %}
|
||||
{% trans "Existing" as existing_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='existing' title=existing_text %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-content">
|
||||
{% if can_create %}
|
||||
<section id="new" class="active nice-padding">
|
||||
{% include "wagtailadmin/workflows/task_chooser/includes/create_tab.html" %}
|
||||
</section>
|
||||
{% endif %}
|
||||
<section id="existing" class="nice-padding{% if not can_create %} active{% endif %}">
|
||||
<div class="tab-content nice-padding">
|
||||
<section
|
||||
id="tab-new"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
aria-labelledby="tab-label-new"
|
||||
hidden
|
||||
>
|
||||
{% include "wagtailadmin/workflows/task_chooser/includes/create_tab.html" %}
|
||||
</section>
|
||||
<section
|
||||
id="tab-existing"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
aria-labelledby="tab-label-existing"
|
||||
hidden
|
||||
>
|
||||
<form class="task-search search-bar" action="{% url 'wagtailadmin_workflows:task_chooser_results' %}" method="GET" novalidate>
|
||||
<ul class="fields">
|
||||
{% for field in search_form %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</form>
|
||||
<div id="search-results" class="listing tasks">
|
||||
{% include "wagtailadmin/workflows/task_chooser/includes/results.html" %}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="nice-padding">
|
||||
<form class="task-search search-bar" action="{% url 'wagtailadmin_workflows:task_chooser_results' %}" method="GET" novalidate>
|
||||
<ul class="fields">
|
||||
{% for field in search_form %}
|
||||
@ -26,5 +56,5 @@
|
||||
<div id="search-results" class="listing tasks">
|
||||
{% include "wagtailadmin/workflows/task_chooser/includes/results.html" %}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -67,7 +67,7 @@
|
||||
{% trans "You haven't created any tasks." %}
|
||||
{% if can_create %}
|
||||
{% blocktrans trimmed %}
|
||||
Why not <a class="create-one-now" href="#">create one now</a>?
|
||||
Why not <a class="create-one-now" href="#tab-new" role="tab">create one now</a>?
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
@ -145,10 +145,11 @@ class TestPageCreation(TestCase, WagtailTestUtils):
|
||||
self.assertEqual(response["Content-Type"], "text/html; charset=utf-8")
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a href="#tab-content" class="active" data-tab="content">Content</a>',
|
||||
'<a id="tab-label-content" href="#tab-content" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
self.assertContains(
|
||||
response, '<a href="#tab-promote" class="" data-tab="promote">Promote</a>'
|
||||
response,
|
||||
'<a id="tab-label-promote" href="#tab-promote" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
# test register_page_action_menu_item hook
|
||||
self.assertContains(
|
||||
@ -215,11 +216,9 @@ class TestPageCreation(TestCase, WagtailTestUtils):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a href="#tab-content" class="active" data-tab="content">Content</a>',
|
||||
)
|
||||
self.assertNotContains(
|
||||
response, '<a href="#tab-promote" class="" data-tab="promote">Promote</a>'
|
||||
'<a id="tab-label-content" href="#tab-content" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
self.assertNotContains(response, "tab-promote")
|
||||
|
||||
def test_create_page_with_custom_tabs(self):
|
||||
"""
|
||||
@ -234,14 +233,15 @@ class TestPageCreation(TestCase, WagtailTestUtils):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a href="#tab-content" class="active" data-tab="content">Content</a>',
|
||||
)
|
||||
self.assertContains(
|
||||
response, '<a href="#tab-promote" class="" data-tab="promote">Promote</a>'
|
||||
'<a id="tab-label-content" href="#tab-content" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a href="#tab-dinosaurs" class="" data-tab="dinosaurs">Dinosaurs</a>',
|
||||
'<a id="tab-label-promote" href="#tab-promote" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a id="tab-label-dinosaurs" href="#tab-dinosaurs" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
|
||||
def test_create_page_with_non_model_field(self):
|
||||
|
@ -419,23 +419,17 @@ class TestTabbedInterface(TestCase):
|
||||
|
||||
# result should contain tab buttons
|
||||
self.assertIn(
|
||||
'<a href="#tab-event-details" class="active" data-tab="event-details">Event details</a>',
|
||||
'<a id="tab-label-event-details" href="#tab-event-details" class="w-tabs__tab shiny" role="tab" aria-selected="false" tabindex="-1">',
|
||||
result,
|
||||
)
|
||||
self.assertIn(
|
||||
'<a href="#tab-speakers" class="" data-tab="speakers">Speakers</a>', result
|
||||
'<a id="tab-label-speakers" href="#tab-speakers" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
result,
|
||||
)
|
||||
|
||||
# result should contain tab panels
|
||||
self.assertIn('<div class="tab-content">', result)
|
||||
self.assertIn(
|
||||
'<section id="tab-event-details" class="shiny active" role="tabpanel" aria-labelledby="tab-label-event-details" data-tab="event-details">',
|
||||
result,
|
||||
)
|
||||
self.assertIn(
|
||||
'<section id="tab-speakers" class=" " role="tabpanel" aria-labelledby="tab-label-speakers" data-tab="speakers">',
|
||||
result,
|
||||
)
|
||||
self.assertIn('aria-labelledby="tab-label-event-details"', result)
|
||||
self.assertIn('aria-labelledby="tab-label-speakers"', result)
|
||||
|
||||
# result should contain rendered content from descendants
|
||||
self.assertIn("Abergavenny sheepdog trials</textarea>", result)
|
||||
|
@ -21,7 +21,7 @@
|
||||
{% block content %}
|
||||
|
||||
{% block header %}
|
||||
{% include "modeladmin/includes/header_with_breadcrumb.html" with title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon tabbed=True %}
|
||||
{% include "modeladmin/includes/header_with_breadcrumb.html" with title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon %}
|
||||
{% endblock %}
|
||||
|
||||
<div>
|
||||
|
@ -35,7 +35,7 @@
|
||||
{% block content %}
|
||||
|
||||
{% block header %}
|
||||
{% include "wagtailadmin/shared/header_with_locale_selector.html" with title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon tabbed=1 merged=1 %}
|
||||
{% include "wagtailadmin/shared/header_with_locale_selector.html" with title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon merged=1 %}
|
||||
{% endblock %}
|
||||
|
||||
<form action="{% block form_action %}{{ view.create_url }}{% endblock %}{% if locale %}?locale={{ locale.language_code }}{% endif %}"{% if is_multipart %} enctype="multipart/form-data"{% endif %} method="POST" novalidate>
|
||||
|
@ -2,7 +2,7 @@
|
||||
{% load i18n wagtailadmin_tags %}
|
||||
|
||||
{% block header %}
|
||||
{% include "modeladmin/includes/header_with_history.html" with title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon tabbed=1 merged=1 latest_log_entry=latest_log_entry history_url=history_url %}
|
||||
{% include "modeladmin/includes/header_with_history.html" with title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon merged=1 latest_log_entry=latest_log_entry history_url=history_url %}
|
||||
{% endblock %}
|
||||
|
||||
{% block form_action %}{{ view.edit_url }}{% endblock %}
|
||||
|
@ -17,7 +17,7 @@
|
||||
{% block content %}
|
||||
|
||||
{% block header %}
|
||||
{% include "modeladmin/includes/header_with_breadcrumb.html" with title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon tabbed=True %}
|
||||
{% include "modeladmin/includes/header_with_breadcrumb.html" with title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon %}
|
||||
{% endblock %}
|
||||
|
||||
<div>
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% block titletag %}{% blocktrans trimmed %}Editing {{ setting_type_name}} - {{ instance }}{% endblocktrans %}{% endblock %}
|
||||
{% block bodyclass %}menu-settings{% endblock %}
|
||||
{% block content %}
|
||||
<header class="nice-padding {% if tabbed %}merged tab-merged{% endif %}">
|
||||
<header class="nice-padding merged">
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<div class="col">
|
||||
|
@ -685,26 +685,21 @@
|
||||
<section id="tabs">
|
||||
<h2>Tabs</h2>
|
||||
|
||||
<ul class="tab-nav" data-tab-nav>
|
||||
<li class="active"><a href="#tab1">Tab 1</a></li>
|
||||
<li><a href="#tab2">Tab 2</a></li>
|
||||
</ul>
|
||||
|
||||
<p>Tabs are currently only used following headers, where they often appear merged with the bottom of the header:</p>
|
||||
|
||||
{% include "wagtailadmin/shared/header.html" with title=title_trans merged=1 %}
|
||||
<ul class="tab-nav merged" data-tab-nav>
|
||||
<li class="active"><a href="#">Tab1</a></li>
|
||||
<li><a href="#">Tab2</a></li>
|
||||
</ul>
|
||||
<div class="w-tabs" data-tabs data-tabs-animate>
|
||||
<div role="tablist" class="w-tabs__list">
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='tab-1' title='Tab 1' %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='tab-2' title='Tab 2' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Tabs can also indicate errors:</p>
|
||||
|
||||
{% include "wagtailadmin/shared/header.html" with title=title_trans merged=1 %}
|
||||
<ul class="tab-nav merged" data-tab-nav>
|
||||
<li class="active"><a href="#" class="errors" data-count="123">Tab1</a></li>
|
||||
<li><a href="#" class="errors" data-count="1">Tab2</a></li>
|
||||
</ul>
|
||||
<div class="w-tabs" data-tabs data-tabs-animate>
|
||||
<div role="tablist" class="w-tabs__list">
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='tab-errors-1' title='Tab 1' errors_count='5' %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='tab-errors-2' title='Tab 2' errors_count='55' %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="breadcrumbs">
|
||||
|
@ -1,34 +1,46 @@
|
||||
{% load i18n wagtailadmin_tags %}
|
||||
{% trans "Choose a document" as choose_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=choose_str tabbed=1 merged=1 icon="doc-full-inverse" %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=choose_str merged=1 icon="doc-full-inverse" %}
|
||||
|
||||
{{ uploadform.media.js }}
|
||||
{{ uploadform.media.css }}
|
||||
|
||||
{% if uploadform %}
|
||||
<ul class="tab-nav merged" data-tab-nav>
|
||||
<li class="{% if not uploadform.errors %}active {% endif %}"><a href="#search">{% trans "Search" %}</a></li>
|
||||
<li class="{% if uploadform.errors %}active {% endif %}"><a href="#upload">{% trans "Upload" %}</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<div class="tab-content">
|
||||
<section id="search" class="{% if not uploadform.errors %}active {% endif %}nice-padding">
|
||||
<form class="document-search search-bar" action="{% url 'wagtaildocs:chooser_results' %}" method="GET" novalidate>
|
||||
<ul class="fields">
|
||||
{% for field in searchform %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
|
||||
{% endfor %}
|
||||
{% if collections %}
|
||||
{% include "wagtailadmin/shared/collection_chooser.html" %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</form>
|
||||
<div id="search-results" class="listing documents">
|
||||
{% include "wagtaildocs/chooser/results.html" %}
|
||||
</div>
|
||||
</section>
|
||||
<div class="w-tabs" data-tabs data-tabs-disable-url>
|
||||
{% if uploadform %}
|
||||
{% include "wagtaildocs/chooser/upload_form.html" with form=uploadform %}
|
||||
<div class="w-tabs__wrapper w-overflow-hidden">
|
||||
{# Using nice-padding and full width class until the modal header is restyled #}
|
||||
<div role="tablist" class="w-tabs__list w-w-full nice-padding">
|
||||
{% trans "Search" as search_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='search' title=search_text %}
|
||||
{% trans "Upload" as upload_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='upload' title=upload_text %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="tab-content nice-padding">
|
||||
<section
|
||||
id="tab-search"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
aria-labelledby="tab-label-search"
|
||||
>
|
||||
<form class="document-search search-bar" action="{% url 'wagtaildocs:chooser_results' %}" method="GET" novalidate>
|
||||
<ul class="fields">
|
||||
{% for field in searchform %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
|
||||
{% endfor %}
|
||||
{% if collections %}
|
||||
{% include "wagtailadmin/shared/collection_chooser.html" %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</form>
|
||||
<div id="search-results" class="listing documents">
|
||||
{% include "wagtaildocs/chooser/results.html" %}
|
||||
</div>
|
||||
</section>
|
||||
{% if uploadform %}
|
||||
{% include "wagtaildocs/chooser/upload_form.html" with form=uploadform %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -25,9 +25,8 @@
|
||||
{% trans "You haven't uploaded any documents." %}
|
||||
{% endif %}
|
||||
{% if uploadform %}
|
||||
{% url 'wagtaildocs:add_multiple' as wagtaildocs_add_document_url %}
|
||||
{% blocktrans trimmed %}
|
||||
Why not <a class="upload-one-now" href="{{ wagtaildocs_add_document_url }}">upload one now</a>?
|
||||
Why not <a class="upload-one-now" href="#tab-upload" role="tab">upload one now</a>?
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
@ -1,5 +1,11 @@
|
||||
{% load i18n wagtailadmin_tags %}
|
||||
<section id="upload" class="{% if form.errors %}active {% endif %}nice-padding">
|
||||
<section
|
||||
id="tab-upload"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="tab-label-upload"
|
||||
>
|
||||
{% include "wagtailadmin/shared/non_field_errors.html" with form=form %}
|
||||
<form class="document-upload" action="{% url 'wagtaildocs:chooser_upload' %}" method="POST" enctype="multipart/form-data" novalidate>
|
||||
{% csrf_token %}
|
||||
|
@ -1,43 +1,53 @@
|
||||
{% load wagtailimages_tags wagtailadmin_tags %}
|
||||
{% load i18n %}
|
||||
{% trans "Choose an image" as choose_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=choose_str merged=1 tabbed=1 icon="image" %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=choose_str merged=1 icon="image" %}
|
||||
|
||||
{{ uploadform.media.js }}
|
||||
{{ uploadform.media.css }}
|
||||
|
||||
{% if uploadform %}
|
||||
<ul class="tab-nav merged" data-tab-nav>
|
||||
<li class="{% if not uploadform.errors %}active{% endif %}"><a href="#search" >{% trans "Search" %}</a></li>
|
||||
<li class="{% if uploadform.errors %}active{% endif %}"><a href="#upload">{% trans "Upload" %}</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<div class="tab-content">
|
||||
<section id="search" class="{% if not uploadform.errors %}active{% endif %} nice-padding">
|
||||
<form class="image-search search-bar" action="{% url 'wagtailimages:chooser_results' %}{% if will_select_format %}?select_format=true{% endif %}" method="GET" autocomplete="off" novalidate>
|
||||
<ul class="fields">
|
||||
{% for field in searchform %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
|
||||
{% endfor %}
|
||||
{% if collections %}
|
||||
{% include "wagtailadmin/shared/collection_chooser.html" %}
|
||||
{% endif %}
|
||||
{% if popular_tags %}
|
||||
<li class="taglist">
|
||||
<h3>{% trans 'Popular tags' %}</h3>
|
||||
{% for tag in popular_tags %}
|
||||
<a class="suggested-tag tag" href="{% url 'wagtailimages:index' %}?tag={{ tag.name|urlencode }}">{{ tag.name }}</a>
|
||||
{% endfor %}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</form>
|
||||
<div id="image-results">
|
||||
{% include "wagtailimages/chooser/results.html" %}
|
||||
</div>
|
||||
</section>
|
||||
<div class="w-tabs" data-tabs data-tabs-disable-url>
|
||||
{% if uploadform %}
|
||||
{% include "wagtailimages/chooser/upload_form.html" with form=uploadform will_select_format=will_select_format %}
|
||||
{# Using nice-padding and full width class until the modal header is restyled #}
|
||||
<div role="tablist" class="w-tabs__list w-w-full nice-padding">
|
||||
{% trans "Search" as search_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='search' title=search_text active=uploadform.errors %}
|
||||
{% trans "Upload" as upload_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='upload' title=upload_text active=uploadform.errors %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="tab-content nice-padding">
|
||||
<section
|
||||
id="tab-search"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
aria-labelledby="tab-label-search"
|
||||
>
|
||||
<form class="image-search search-bar" action="{% url 'wagtailimages:chooser_results' %}{% if will_select_format %}?select_format=true{% endif %}" method="GET" autocomplete="off" novalidate>
|
||||
<ul class="fields">
|
||||
{% for field in searchform %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
|
||||
{% endfor %}
|
||||
{% if collections %}
|
||||
{% include "wagtailadmin/shared/collection_chooser.html" %}
|
||||
{% endif %}
|
||||
{% if popular_tags %}
|
||||
<li class="taglist">
|
||||
<h3>{% trans 'Popular tags' %}</h3>
|
||||
{% for tag in popular_tags %}
|
||||
<a class="suggested-tag tag" href="{% url 'wagtailimages:index' %}?tag={{ tag.name|urlencode }}">{{ tag.name }}</a>
|
||||
{% endfor %}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</form>
|
||||
<div id="image-results">
|
||||
{% include "wagtailimages/chooser/results.html" %}
|
||||
</div>
|
||||
</section>
|
||||
{% if uploadform %}
|
||||
{% include "wagtailimages/chooser/upload_form.html" with form=uploadform will_select_format=will_select_format %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,11 @@
|
||||
{% load i18n wagtailadmin_tags %}
|
||||
|
||||
<section id="upload" class="{% if form.errors %}active{% endif %} nice-padding">
|
||||
<section
|
||||
id="tab-upload"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="tab-label-upload"
|
||||
>
|
||||
{% include "wagtailadmin/shared/non_field_errors.html" with form=form %}
|
||||
<form class="image-upload" action="{% url 'wagtailimages:chooser_upload' %}{% if will_select_format %}?select_format=true{% endif %}" method="POST" enctype="multipart/form-data" novalidate>
|
||||
{% csrf_token %}
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% block titletag %}{% blocktrans trimmed with snippet_type_name=model_opts.verbose_name %}New {{ snippet_type_name }}{% endblocktrans %}{% endblock %}
|
||||
{% block content %}
|
||||
{% trans "New" as new_str %}
|
||||
{% include "wagtailadmin/shared/header_with_locale_selector.html" with title=new_str subtitle=model_opts.verbose_name icon="snippet" tabbed=1 merged=1 locale=locale translations=translations only %}
|
||||
{% include "wagtailadmin/shared/header_with_locale_selector.html" with title=new_str subtitle=model_opts.verbose_name icon="snippet" merged=1 locale=locale translations=translations only %}
|
||||
|
||||
<form action="{{ action_url }}" method="POST" novalidate{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
|
||||
{% csrf_token %}
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% block titletag %}{% blocktrans trimmed with snippet_type_name=model_opts.verbose_name %}Editing {{ snippet_type_name }} - {{ instance }}{% endblocktrans %}{% endblock %}
|
||||
{% block content %}
|
||||
{% trans "Editing" as editing_str %}
|
||||
{% include "wagtailsnippets/snippets/_header_with_history.html" with title=editing_str subtitle=instance icon="snippet" tabbed=1 merged=1 %}
|
||||
{% include "wagtailsnippets/snippets/_header_with_history.html" with title=editing_str subtitle=instance icon="snippet" merged=1 %}
|
||||
|
||||
<div class="row row-flush">
|
||||
|
||||
|
@ -372,19 +372,7 @@ class TestSnippetCreateView(TestCase, WagtailTestUtils):
|
||||
response = self.get()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailsnippets/snippets/create.html")
|
||||
self.assertNotContains(
|
||||
response, '<ul data-tab-nav role="tablist" data-current-tab="advert">'
|
||||
)
|
||||
self.assertNotContains(
|
||||
response,
|
||||
'<a href="#tab-advert" class="active" data-tab="advert">Advert</a>',
|
||||
html=True,
|
||||
)
|
||||
self.assertNotContains(
|
||||
response,
|
||||
'<a href="#tab-other" class="" data-tab="other">Other</a>',
|
||||
html=True,
|
||||
)
|
||||
self.assertNotContains(response, 'role="tablist"', html=True)
|
||||
|
||||
def test_snippet_with_tabbed_interface(self):
|
||||
response = self.client.get(
|
||||
@ -393,18 +381,14 @@ class TestSnippetCreateView(TestCase, WagtailTestUtils):
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailsnippets/snippets/create.html")
|
||||
self.assertContains(response, 'role="tablist"')
|
||||
self.assertContains(
|
||||
response, '<ul data-tab-nav role="tablist" data-current-tab="advert">'
|
||||
response,
|
||||
'<a id="tab-label-advert" href="#tab-advert" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a href="#tab-advert" class="active" data-tab="advert">Advert</a>',
|
||||
html=True,
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a href="#tab-other" class="" data-tab="other">Other</a>',
|
||||
html=True,
|
||||
'<a id="tab-label-other" href="#tab-other" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
|
||||
def test_create_with_limited_permissions(self):
|
||||
@ -698,17 +682,7 @@ class TestSnippetEditView(BaseTestSnippetEditView):
|
||||
response = self.get()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailsnippets/snippets/edit.html")
|
||||
self.assertNotContains(
|
||||
response, '<ul data-tab-nav role="tablist" data-current-tab="advert">'
|
||||
)
|
||||
self.assertNotContains(
|
||||
response,
|
||||
'<a href="#advert" class="active" data-tab="advert">Advert</a>',
|
||||
html=True,
|
||||
)
|
||||
self.assertNotContains(
|
||||
response, '<a href="#other" class="" data-tab="other">Other</a>', html=True
|
||||
)
|
||||
self.assertNotContains(response, 'role="tablist"')
|
||||
|
||||
# "Last updated" timestamp should be present
|
||||
self.assertContains(
|
||||
@ -914,18 +888,14 @@ class TestEditTabbedSnippet(BaseTestSnippetEditView):
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailsnippets/snippets/edit.html")
|
||||
self.assertContains(response, 'role="tablist"')
|
||||
self.assertContains(
|
||||
response, '<ul data-tab-nav role="tablist" data-current-tab="advert">'
|
||||
response,
|
||||
'<a id="tab-label-advert" href="#tab-advert" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a href="#tab-advert" class="active" data-tab="advert">Advert</a>',
|
||||
html=True,
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a href="#tab-other" class="" data-tab="other">Other</a>',
|
||||
html=True,
|
||||
'<a id="tab-label-other" href="#tab-other" class="w-tabs__tab " role="tab" aria-selected="false" tabindex="-1">',
|
||||
)
|
||||
|
||||
|
||||
|
@ -5,46 +5,64 @@
|
||||
{% block content %}
|
||||
|
||||
{% trans "Add user" as add_user_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=add_user_str merged=1 tabbed=1 icon="user" %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=add_user_str merged=1 icon="user" %}
|
||||
|
||||
<ul class="tab-nav merged" data-tab-nav>
|
||||
<li class="active"><a href="#account">{% trans "Account" %}</a></li>
|
||||
<li><a href="#roles">{% trans "Roles" %}</a></li>
|
||||
</ul>
|
||||
|
||||
<form action="{% url 'wagtailusers_users:add' %}" method="POST" novalidate{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
|
||||
<div class="tab-content">
|
||||
{% csrf_token %}
|
||||
<section id="account" class="active nice-padding">
|
||||
<ul class="fields">
|
||||
{% block fields %}
|
||||
{% if form.separate_username_field %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.username_field %}
|
||||
{% endif %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.email %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.first_name %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.last_name %}
|
||||
{% block extra_fields %}{% endblock extra_fields %}
|
||||
{% if form.password1 %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.password1 %}
|
||||
{% endif %}
|
||||
{% if form.password2 %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.password2 %}
|
||||
{% endif %}
|
||||
{% endblock fields %}
|
||||
|
||||
<li><a href="#roles" class="button lowpriority tab-toggle icon icon-arrow-right-after">{% trans "Roles" %}</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="roles" class="nice-padding">
|
||||
<ul class="fields">
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.is_superuser %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.groups %}
|
||||
<li><button class="button">{% trans "Add user" %}</button></li>
|
||||
</ul>
|
||||
</section>
|
||||
<div class="w-tabs" data-tabs data-tabs-animate>
|
||||
<div class="w-tabs__wrapper">
|
||||
<div role="tablist" class="w-tabs__list nice-padding">
|
||||
{% trans "Account" as account_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='account' title=account_text %}
|
||||
{% trans "Roles" as roles_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='roles' title=roles_text %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form action="{% url 'wagtailusers_users:add' %}" method="POST" novalidate{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
|
||||
<div class="tab-content nice-padding">
|
||||
{% csrf_token %}
|
||||
<section
|
||||
id="tab-account"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="tab-label-account"
|
||||
>
|
||||
<ul class="fields">
|
||||
{% block fields %}
|
||||
{% if form.separate_username_field %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.username_field %}
|
||||
{% endif %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.email %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.first_name %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.last_name %}
|
||||
{% block extra_fields %}{% endblock extra_fields %}
|
||||
{% if form.password1 %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.password1 %}
|
||||
{% endif %}
|
||||
{% if form.password2 %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.password2 %}
|
||||
{% endif %}
|
||||
{% endblock fields %}
|
||||
|
||||
<li><a href="#tab-roles" role="tab" class="button lowpriority icon icon-arrow-right-after">{% trans "Roles" %}</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section
|
||||
id="tab-roles"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="tab-label-roles"
|
||||
>
|
||||
<ul class="fields">
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.is_superuser %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.groups %}
|
||||
<li><button class="button">{% trans "Add user" %}</button></li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
|
@ -1,67 +1,85 @@
|
||||
{% extends "wagtailadmin/base.html" %}
|
||||
{% load wagtailimages_tags %}
|
||||
{% load i18n %}
|
||||
{% block titletag %}{% trans "Editing" %} {{ user.get_username}}{% endblock %}
|
||||
{% block titletag %}{% trans "Editing" %} {{ user.get_username }}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
{% trans "Editing" as editing_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=editing_str subtitle=user.get_username merged=1 tabbed=1 icon="user" %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=editing_str subtitle=user.get_username merged=1 icon="user" %}
|
||||
|
||||
<ul class="tab-nav merged" data-tab-nav>
|
||||
<li class="active"><a href="#account">{% trans "Account" %}</a></li>
|
||||
<li><a href="#roles">{% trans "Roles" %}</a></li>
|
||||
</ul>
|
||||
|
||||
<form action="{% url 'wagtailusers_users:edit' user.pk %}" method="POST" novalidate{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
|
||||
<div class="tab-content">
|
||||
{% csrf_token %}
|
||||
|
||||
<section id="account" class="active nice-padding">
|
||||
<ul class="fields">
|
||||
{% block fields %}
|
||||
{% if form.separate_username_field %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.username_field %}
|
||||
{% endif %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.email %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.first_name %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.last_name %}
|
||||
{% block extra_fields %}{% endblock extra_fields %}
|
||||
{% if form.password1 %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.password1 %}
|
||||
{% endif %}
|
||||
{% if form.password2 %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.password2 %}
|
||||
{% endif %}
|
||||
{% if form.is_active %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.is_active %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock fields %}
|
||||
<li>
|
||||
<input type="submit" value="{% trans 'Save' %}" class="button" />
|
||||
{% if can_delete %}
|
||||
<a href="{% url 'wagtailusers_users:delete' user.pk %}" class="button button-secondary no">{% trans "Delete user" %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="roles" class="nice-padding">
|
||||
<ul class="fields">
|
||||
{% if form.is_superuser %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.is_superuser %}
|
||||
{% endif %}
|
||||
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.groups %}
|
||||
<li>
|
||||
<input type="submit" value="{% trans 'Save' %}" class="button" />
|
||||
{% if can_delete %}
|
||||
<a href="{% url 'wagtailusers_users:delete' user.pk %}" class="button button-secondary no">{% trans "Delete user" %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<div class="w-tabs" data-tabs data-tabs-animate>
|
||||
<div class="w-tabs__wrapper">
|
||||
<div role="tablist" class="w-tabs__list nice-padding">
|
||||
{% trans "Account" as account_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='account' title=account_text %}
|
||||
{% trans "Roles" as roles_text %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id='roles' title=roles_text %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form action="{% url 'wagtailusers_users:edit' user.pk %}" method="POST" novalidate{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
|
||||
<div class="tab-content nice-padding">
|
||||
{% csrf_token %}
|
||||
|
||||
<section
|
||||
id="tab-account"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="tab-label-account"
|
||||
>
|
||||
<ul class="fields">
|
||||
{% block fields %}
|
||||
{% if form.separate_username_field %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.username_field %}
|
||||
{% endif %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.email %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.first_name %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.last_name %}
|
||||
{% block extra_fields %}{% endblock extra_fields %}
|
||||
{% if form.password1 %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.password1 %}
|
||||
{% endif %}
|
||||
{% if form.password2 %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.password2 %}
|
||||
{% endif %}
|
||||
{% if form.is_active %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.is_active %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock fields %}
|
||||
<li>
|
||||
<input type="submit" value="{% trans 'Save' %}" class="button"/>
|
||||
{% if can_delete %}
|
||||
<a href="{% url 'wagtailusers_users:delete' user.pk %}" class="button button-secondary no">{% trans "Delete user" %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section
|
||||
id="tab-roles"
|
||||
class="w-tabs__panel"
|
||||
role="tabpanel"
|
||||
hidden
|
||||
aria-labelledby="tab-label-roles"
|
||||
>
|
||||
<ul class="fields">
|
||||
{% if form.is_superuser %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.is_superuser %}
|
||||
{% endif %}
|
||||
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=form.groups %}
|
||||
<li>
|
||||
<input type="submit" value="{% trans 'Save' %}" class="button"/>
|
||||
{% if can_delete %}
|
||||
<a href="{% url 'wagtailusers_users:delete' user.pk %}" class="button button-secondary no">{% trans "Delete user" %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
|
Loading…
Reference in New Issue
Block a user