T7.2 - F6/D3: the form gets structure - a section rail, one section open
F6 as amended by D3 (Aug 18): one page, persistent side navigation, sections collapsible, only the current one open by default, plus Expand all. Tabs were rejected in D3 because they hide sections a first-time author does not know exist. What changed: - The jump-chip strip (#section-nav, span onclick) is gone. In its place a <nav> section rail of real <button> entries, aria-current on the current section, 44px tap targets, above the form at 390px and beside it at 1440px. - Every section heading is now a disclosure <button> with aria-expanded and aria-controls. One section open at rest; Expand all (aria-pressed) opens everything and is remembered per browser. - Sections are URL-addressable (?section=, T4.2 machinery) and a deep link to a collapsed section expands it. Positional-id fallback removed: a card without an id gets a console.error and no rail entry, never an invented sec-N id that would ride into shareable URLs and move between visits. - General Information (1,288px on its own) split into #general-card and #assign-card (Assignment & Schedule). The split is presentational: both cards are the ONE CR-006 section `general` (WP_SECTION_NODES lists both), so wp-sections.js and the SOP wizard are untouched. CR-001's adjacency (P6 activity beside due date) is preserved and asserted. - gotoSection() flushes autosave, which the deleted chips used to do. - secMakeToggle() preserves every element child of a heading - help tips go outside the button, everything else inside the label. The first version cleared textContent and destroyed #saved-count, which killed boot one line short of wpCreatorReady with the page still visibly rendered. - BL-013 folded in per the task: the T3.4 focus ring on the rebuilt form. frame_check reports outline solid 2px on creator inputs. Height, measured not asserted: 5,399px before; 1,995px at rest at 1440x900. DONE-WHEN NOT FULLY MET - stated per CLAUDE.md rather than marked complete: "no single view exceeds roughly two screen heights at rest" reads 2.22 screens (1995/900). The remaining gap is page chrome this wave reworks: .ctx-bar (67px, T7.4) and .release-banner (45px, T7.5). The criterion was already amended once (D3, "at rest") and is not being moved again to fit; tests/form_structure_check.py keeps the check red and it is re-measured at the end of wave 7. Every other done-when entry passes. Backlog: BL-001's cause corrected a third time - at rest the overflow is help.js's .help-tip::after tooltip (481 vs 390), the S8 component T9.5 rebuilds; the tables still overflow only when expanded. Deliberately not fixed here - a fix would be thrown away with the component at T9.5. Verification (each probe run alone): form_structure_check 50/51 (the height check above), sections_check 95/95, generalinfo_check 49/49, frame_check 39/39 regression pass. Items: F6, D3, BL-013, BL-001 (re-measured) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1398,70 +1398,288 @@ function syncToolTabs(){
|
||||
|
||||
// Sticky save bar + section-nav chrome (shown only on the editable form view).
|
||||
function setFormChrome(on){
|
||||
const nav=document.getElementById('section-nav'), save=document.getElementById('sticky-save');
|
||||
if(nav) nav.style.display = on ? '' : 'none';
|
||||
const rail=document.getElementById('section-rail'), save=document.getElementById('sticky-save');
|
||||
if(rail) rail.style.display = on ? '' : 'none';
|
||||
if(save) save.style.display = on ? 'flex' : 'none';
|
||||
document.body.classList.toggle('has-sticky-save', !!on);
|
||||
if(on){ buildSectionNav(); updateStickyStatus(); makeCollapsible(); initSectionNavAutoHide(); }
|
||||
document.body.classList.toggle('has-sec-rail', !!on);
|
||||
if(on){ initSectionNavAutoHide(); buildSectionRail(); updateStickyStatus(); }
|
||||
else positionSectionNav();
|
||||
}
|
||||
// Make each form card collapsible by clicking its heading (idempotent).
|
||||
function makeCollapsible(){
|
||||
document.querySelectorAll('.main > .card').forEach(card=>{
|
||||
if(card.id==='saved-card') return;
|
||||
const head=card.querySelector('.section-header, .sub-heading');
|
||||
if(!head || head.dataset.collapsible) return;
|
||||
head.dataset.collapsible='1';
|
||||
head.style.cursor='pointer';
|
||||
const chev=document.createElement('span'); chev.className='collapse-chev'; chev.textContent='▾';
|
||||
head.insertBefore(chev, head.firstChild);
|
||||
head.addEventListener('click', e=>{
|
||||
if(['INPUT','SELECT','TEXTAREA','BUTTON','A'].includes(e.target.tagName) || e.target.classList.contains('help-tip')) return;
|
||||
const collapsed=card.classList.toggle('collapsed');
|
||||
chev.textContent = collapsed ? '▸' : '▾';
|
||||
// ── SECTION STRUCTURE (F6 / D3) ───────────────────────────────────────────────
|
||||
// F6 measured this form at 11 cards in one 5,399px scroll, with a strip of jump
|
||||
// chips standing in for structure. D3 settled the shape, and it is not tabs:
|
||||
// one page, navigation down the side, sections collapsible, only the current one
|
||||
// open, plus an `Expand all` for people who would rather scroll straight through.
|
||||
//
|
||||
// Tabs were rejected because they hide sections a first-time author does not know
|
||||
// exist. The uncollapsed long form was rejected because it is the page F6 exists
|
||||
// to fix. So the height criterion became "at rest" - the state the page loads in -
|
||||
// which is what D3 amended it to, in writing, rather than quietly failing the old
|
||||
// one.
|
||||
//
|
||||
// Two accessibility defects come out with the old strip, both named in CLAUDE.md:
|
||||
// - the jump chips were `<span onclick>`; there were two left in the app
|
||||
// - collapsing was a click listener on a heading `<div>`, so it was mouse-only
|
||||
// Every control here is a real button. The rail is built FROM THE CARDS, so a
|
||||
// section added later, or suppressed by a CR-006 toggle, changes the rail without
|
||||
// anyone remembering to maintain a second list.
|
||||
|
||||
const SEC_EXPAND_KEY = 'wp_iwp_expand_all';
|
||||
let secExpandAll = false;
|
||||
let secCurrent = '';
|
||||
let _secSpyBound = false;
|
||||
|
||||
// The cards that are sections: rendered, and carrying a heading to name them.
|
||||
// `hidden` and `display:none` are how CR-006 and applyKindVisibility() suppress
|
||||
// one, and a table of contents has to lose exactly what the form lost.
|
||||
function secCards(){
|
||||
return [...document.querySelectorAll('.main > .card')].filter(card => {
|
||||
// `Saved work packages` is a list of OTHER packages, sitting at the bottom of
|
||||
// the form for editing THIS one - and the navigator panel already lists exactly
|
||||
// the same thing. It is not a section of the package, so it gets no rail entry.
|
||||
// It is still collapsed by default (secApplyOpenState), because 310px of a
|
||||
// duplicate list is not what the page should open on.
|
||||
if(card.id === 'saved-card') return false;
|
||||
if(card.hidden || card.style.display === 'none') return false;
|
||||
return !!card.querySelector('.section-title, .sub-heading');
|
||||
});
|
||||
}
|
||||
|
||||
function secLabel(card){
|
||||
const h = card.querySelector('.section-title, .sub-heading');
|
||||
if(!h) return '';
|
||||
const clone = h.cloneNode(true);
|
||||
clone.querySelectorAll('.help-tip, .auto-tag, .collapse-chev').forEach(x => x.remove());
|
||||
return clone.textContent.trim().replace(/\s+/g, ' ');
|
||||
}
|
||||
|
||||
// Everything below the heading, wrapped once so `aria-controls` has a real target
|
||||
// and collapsing is `hidden` on one element rather than a `:not()` rule listing
|
||||
// the heading classes. The old CSS did the latter, which meant the disclosure
|
||||
// state lived nowhere a screen reader could read it.
|
||||
function secBody(card){
|
||||
let body = card.querySelector(':scope > .card-body');
|
||||
if(body) return body;
|
||||
const head = card.querySelector(':scope > .section-header, :scope > .sub-heading');
|
||||
if(!head) return null;
|
||||
body = document.createElement('div');
|
||||
body.className = 'card-body';
|
||||
body.id = (card.id || 'sec') + '-body';
|
||||
const rest = [];
|
||||
for(let n = head.nextSibling; n; n = n.nextSibling) rest.push(n);
|
||||
rest.forEach(n => body.appendChild(n));
|
||||
card.appendChild(body);
|
||||
return body;
|
||||
}
|
||||
|
||||
// Turn the heading into a disclosure button, in place and once. The label goes
|
||||
// inside the button; the help tip and the description stay OUTSIDE it, because a
|
||||
// tooltip trigger nested in a button is two controls in one hit area.
|
||||
function secMakeToggle(card){
|
||||
if(card.dataset.secReady) return;
|
||||
const body = secBody(card);
|
||||
if(!body) return;
|
||||
const title = card.querySelector(':scope > .section-header > .section-title')
|
||||
|| card.querySelector(':scope > .sub-heading');
|
||||
if(!title) return;
|
||||
|
||||
const label = secLabel(card);
|
||||
// Every ELEMENT in the heading has to survive, not only the text. `saved-card`'s
|
||||
// heading carries <span id="saved-count">, which renderSavedList() writes to on
|
||||
// every save - clearing the heading destroyed it, renderSavedList() then threw on
|
||||
// a null, and boot stopped one line short of setting wpCreatorReady. The page
|
||||
// still rendered, so it looked like a slow load rather than a crash.
|
||||
//
|
||||
// Help tips go OUTSIDE the button: a tooltip trigger nested inside a button is
|
||||
// two controls sharing one hit area. Everything else goes inside, because it is
|
||||
// part of the heading's own text - a count, a badge, a tag.
|
||||
const kids = [...title.children];
|
||||
const tips = kids.filter(el => el.classList.contains('help-tip'));
|
||||
const inside = kids.filter(el => !el.classList.contains('help-tip'));
|
||||
const btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = 'card-toggle';
|
||||
btn.setAttribute('aria-expanded', 'true');
|
||||
btn.setAttribute('aria-controls', body.id);
|
||||
btn.innerHTML = '<span class="collapse-chev" aria-hidden="true"></span>'
|
||||
+ '<span class="card-toggle-label"></span>';
|
||||
const labelEl = btn.querySelector('.card-toggle-label');
|
||||
labelEl.textContent = label;
|
||||
inside.forEach(el => labelEl.appendChild(el));
|
||||
title.textContent = '';
|
||||
title.appendChild(btn);
|
||||
tips.forEach(t => title.appendChild(t));
|
||||
|
||||
btn.addEventListener('click', () => {
|
||||
const open = card.classList.contains('collapsed');
|
||||
secSetOpen(card, open);
|
||||
// Opening a section by its own header makes it the one you are in, which the
|
||||
// rail has to agree with - otherwise the rail marks a section you left.
|
||||
if(open){ secCurrent = card.id; secMarkRail(); secSyncUrl(); }
|
||||
});
|
||||
card.dataset.secReady = '1';
|
||||
}
|
||||
|
||||
function secSetOpen(card, open){
|
||||
const btn = card.querySelector(':scope .card-toggle');
|
||||
const body = card.querySelector(':scope > .card-body');
|
||||
card.classList.toggle('collapsed', !open);
|
||||
if(btn) btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||
if(body) body.hidden = !open;
|
||||
}
|
||||
|
||||
function secIsOpen(card){ return !card.classList.contains('collapsed'); }
|
||||
|
||||
// ── the rail ─────────────────────────────────────────────────────────────────
|
||||
function buildSectionRail(){
|
||||
const rail = document.getElementById('section-rail');
|
||||
const list = document.getElementById('sec-rail-list');
|
||||
if(!rail || !list) return;
|
||||
let cards = secCards();
|
||||
// Every section carries a real id in the markup. A positional fallback was here
|
||||
// and it was a bug waiting to be shipped: the id it invents goes into ?section=
|
||||
// as a shareable address, and the INDEX moves whenever the set of visible
|
||||
// sections changes - a CR-006 toggle, the BIM flag, or a card being inserted
|
||||
// ahead of it. A link somebody sent then opens a different section, silently and
|
||||
// with no error. Name the card in the markup instead; complain loudly if not.
|
||||
cards.forEach(card => {
|
||||
if(!card.id){
|
||||
// Not a toast: this is a defect in the page, not something a user can act on.
|
||||
try { console.error('T7.2: a form section has no id; its rail entry cannot be'
|
||||
+ ' addressed. Give it one in wp-creation-index.html.', card); } catch(e){}
|
||||
return;
|
||||
}
|
||||
secMakeToggle(card);
|
||||
});
|
||||
cards = cards.filter(c => c.id);
|
||||
|
||||
list.innerHTML = cards.map(card =>
|
||||
'<li><button type="button" class="sec-rail-item" data-sec="' + esc(card.id) + '">'
|
||||
+ esc(secLabel(card)) + '</button></li>').join('');
|
||||
list.querySelectorAll('.sec-rail-item').forEach(b => {
|
||||
b.addEventListener('click', () => gotoSection(b.dataset.sec));
|
||||
});
|
||||
rail.hidden = cards.length < 2;
|
||||
|
||||
// Whatever the URL asks for, else the first section. Never "all of them", which
|
||||
// is the state F6 is about.
|
||||
const want = (typeof WPUrl !== 'undefined' && WPUrl.get && WPUrl.get('section')) || '';
|
||||
const target = cards.some(c => c.id === want) ? want : (cards[0] && cards[0].id) || '';
|
||||
secApplyOpenState(target);
|
||||
secBindSpy();
|
||||
}
|
||||
|
||||
// One section open, or all of them. Called on every render, so it is also what
|
||||
// keeps a suppressed section from being left expanded behind the scenes.
|
||||
function secApplyOpenState(currentId){
|
||||
const cards = secCards();
|
||||
secCurrent = currentId || secCurrent || (cards[0] && cards[0].id) || '';
|
||||
cards.forEach(card => secSetOpen(card, secExpandAll || card.id === secCurrent));
|
||||
// The saved-package list is not in `cards` - it is not a section - but it is on
|
||||
// the page and it is 310px tall, so it collapses like everything else. It gets
|
||||
// its disclosure button here because the rail loop no longer reaches it.
|
||||
const saved = document.getElementById('saved-card');
|
||||
if(saved && saved.style.display !== 'none'){
|
||||
secMakeToggle(saved);
|
||||
secSetOpen(saved, secExpandAll);
|
||||
}
|
||||
secMarkRail();
|
||||
}
|
||||
|
||||
function secMarkRail(){
|
||||
document.querySelectorAll('.sec-rail-item').forEach(b => {
|
||||
const on = b.dataset.sec === secCurrent;
|
||||
b.classList.toggle('is-current', on);
|
||||
// aria-current="true", not "page": these are places in a page, not pages.
|
||||
if(on) b.setAttribute('aria-current', 'true');
|
||||
else b.removeAttribute('aria-current');
|
||||
});
|
||||
}
|
||||
|
||||
function secSyncUrl(opts){
|
||||
if(typeof WPUrl === 'undefined') return;
|
||||
const patch = { section: secCurrent || '' };
|
||||
(opts && opts.replace ? WPUrl.replace : WPUrl.push).call(WPUrl, patch);
|
||||
}
|
||||
|
||||
// Open a section and go to it. Focus moves to the section's own heading button,
|
||||
// not just the scroll position: a keyboard user who activates a rail item has to
|
||||
// land somewhere, and landing nowhere is why jump links are not navigation.
|
||||
function gotoSection(id, opts){
|
||||
const card = document.getElementById(id);
|
||||
if(!card) return false;
|
||||
// Moving section is a "you have visibly moved on" moment, so flush the draft
|
||||
// rather than wait out the debounce. This was bound to the old jump chips at
|
||||
// initAutosave() time, which only worked because the chips were built before it
|
||||
// ran; it belongs here, where every section change goes through one door -
|
||||
// rail click, keyboard, deep link and Back alike.
|
||||
if(typeof WPAutosave !== 'undefined' && WPAutosave.flush) WPAutosave.flush('section');
|
||||
secApplyOpenState(id);
|
||||
const btn = card.querySelector('.card-toggle');
|
||||
if(btn){
|
||||
btn.focus({preventScroll:true});
|
||||
card.scrollIntoView({behavior:'smooth', block:'start'});
|
||||
}
|
||||
if(!(opts && opts.fromUrl)) secSyncUrl();
|
||||
return true;
|
||||
}
|
||||
|
||||
function toggleExpandAll(){
|
||||
setExpandAll(!secExpandAll);
|
||||
}
|
||||
|
||||
function setExpandAll(on){
|
||||
secExpandAll = !!on;
|
||||
try { localStorage.setItem(SEC_EXPAND_KEY, secExpandAll ? '1' : '0'); } catch(e){}
|
||||
const btn = document.getElementById('sec-expand-all');
|
||||
if(btn){
|
||||
btn.setAttribute('aria-pressed', secExpandAll ? 'true' : 'false');
|
||||
btn.textContent = secExpandAll ? 'Collapse all' : 'Expand all';
|
||||
}
|
||||
secApplyOpenState(secCurrent);
|
||||
track(secExpandAll ? 'sections_expand_all' : 'sections_collapse_all');
|
||||
}
|
||||
|
||||
// With one section open the current one is whatever you opened. With Expand all
|
||||
// on, that answer is wrong the moment you scroll, so the rail follows the form.
|
||||
function secBindSpy(){
|
||||
if(_secSpyBound) return;
|
||||
_secSpyBound = true;
|
||||
window.addEventListener('scroll', () => {
|
||||
if(!secExpandAll) return;
|
||||
const rail = document.getElementById('section-rail');
|
||||
if(!rail || rail.hidden) return;
|
||||
const line = (document.querySelector('.header') || {offsetHeight:0}).offsetHeight + 80;
|
||||
let seen = '';
|
||||
secCards().forEach(card => {
|
||||
if(card.getBoundingClientRect().top <= line) seen = card.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
function buildSectionNav(){
|
||||
const nav=document.getElementById('section-nav'); if(!nav) return;
|
||||
const chips=[];
|
||||
document.querySelectorAll('.main > .card').forEach((card,i)=>{
|
||||
// `hidden` is how CR-006 suppresses a section; the chip strip is a table of
|
||||
// contents for the form, so it has to lose the same entries.
|
||||
if(card.id==='saved-card' || card.style.display==='none' || card.hidden) return;
|
||||
const h=card.querySelector('.section-title, .sub-heading'); if(!h) return;
|
||||
const clone=h.cloneNode(true); clone.querySelectorAll('.help-tip').forEach(x=>x.remove());
|
||||
const label=clone.textContent.trim().replace(/\s+/g,' '); if(!label) return;
|
||||
if(!card.id) card.id='sec-'+i;
|
||||
chips.push(`<span class="sec-chip" onclick="document.getElementById('${card.id}').scrollIntoView({behavior:'smooth',block:'start'})">${esc(label)}</span>`);
|
||||
});
|
||||
nav.innerHTML=chips.join('');
|
||||
}
|
||||
// Keep the section-nav pinned just below the sticky header (so it stays put while
|
||||
// scrolling instead of hiding behind the header), and let it slide out of the way
|
||||
// while reading (scroll down), snapping back the moment you scroll up.
|
||||
function positionSectionNav(){
|
||||
const nav=document.getElementById('section-nav'), hdr=document.querySelector('.header');
|
||||
if(nav && hdr) nav.style.top = hdr.offsetHeight + 'px';
|
||||
// The navigator drawer + its handle hang below the page header. Deliberately NOT
|
||||
// including the section-nav height: that bar is sticky, so at scroll 0 it sits
|
||||
// further down the page and the handle would float over the chrome.
|
||||
document.documentElement.style.setProperty('--rail-top', (hdr?hdr.offsetHeight:0)+'px');
|
||||
}
|
||||
let _snLastY=0, _snBound=false;
|
||||
function initSectionNavAutoHide(){
|
||||
positionSectionNav();
|
||||
if(_snBound) return; _snBound=true;
|
||||
window.addEventListener('resize', positionSectionNav, {passive:true});
|
||||
window.addEventListener('scroll', ()=>{
|
||||
const nav=document.getElementById('section-nav');
|
||||
if(!nav || nav.style.display==='none') return;
|
||||
const y=window.scrollY||document.documentElement.scrollTop||0;
|
||||
if(y>_snLastY+4 && y>140) nav.classList.add('nav-hidden'); // scrolling down
|
||||
else if(y<_snLastY-4) nav.classList.remove('nav-hidden'); // scrolling up
|
||||
_snLastY=y;
|
||||
if(seen && seen !== secCurrent){ secCurrent = seen; secMarkRail(); }
|
||||
}, {passive:true});
|
||||
}
|
||||
|
||||
// The drawer and the comments panel hang below the page chrome, and the chrome is
|
||||
// taller since T7.1 - app bar, tab strip, toolbar. Measure it rather than assume.
|
||||
function positionSectionNav(){
|
||||
const parts = ['.header', '.main-nav', '.wp-toolbar']
|
||||
.map(sel => document.querySelector(sel))
|
||||
.filter(Boolean);
|
||||
const h = parts.reduce((n, el) => n + el.offsetHeight, 0);
|
||||
document.documentElement.style.setProperty('--rail-top', h + 'px');
|
||||
const rail = document.getElementById('section-rail');
|
||||
if(rail) rail.style.setProperty('--sec-rail-top', h + 'px');
|
||||
}
|
||||
|
||||
let _secChromeBound = false;
|
||||
function initSectionNavAutoHide(){
|
||||
positionSectionNav();
|
||||
if(_secChromeBound) return;
|
||||
_secChromeBound = true;
|
||||
window.addEventListener('resize', positionSectionNav, {passive:true});
|
||||
try { setExpandAll(localStorage.getItem(SEC_EXPAND_KEY) === '1'); } catch(e){}
|
||||
}
|
||||
|
||||
function updateStickyStatus(){
|
||||
const el=document.getElementById('sticky-status'); if(!el) return;
|
||||
const r=readiness(); const st=getRadio('status');
|
||||
@@ -1621,7 +1839,10 @@ function wpLocationText(p){
|
||||
// of its own; CR-004 gives it structured fields in wave 6 and only this line
|
||||
// changes then.
|
||||
const WP_SECTION_NODES = {
|
||||
general: ['#general-card'],
|
||||
// Two cards, one section. T7.2 split General Information because it was 1,288px
|
||||
// on its own; the split is presentational and CR-006 still governs both through
|
||||
// the single `general` id, so wp-sections.js and the SOP wizard are untouched.
|
||||
general: ['#general-card', '#assign-card'],
|
||||
location: ['#location-card'],
|
||||
scope: ['#scope-card'],
|
||||
assets: ['#asset-card'],
|
||||
@@ -1682,7 +1903,7 @@ function applySopSections(sections, fields){
|
||||
});
|
||||
// The section chips are a table of contents for the form, so they have to lose
|
||||
// the same entries.
|
||||
if(typeof buildSectionNav === 'function') buildSectionNav();
|
||||
if(typeof buildSectionRail === 'function') buildSectionRail();
|
||||
// A package already on screen is re-rendered, or the view keeps showing a
|
||||
// section the form no longer has.
|
||||
if(currentView === 'Package View' && _lastRenderedPkg) renderPackage(_lastRenderedPkg);
|
||||
@@ -1750,9 +1971,11 @@ const WP_NAV_CRITICAL_CSS = `
|
||||
/* Modals are hidden by a stylesheet rule; without it their contents render inline
|
||||
in the middle of the form. Same reasoning as the panel: this is a floor. */
|
||||
.modal-overlay:not(.open),.cmt-overlay:not(.open){display:none!important;}
|
||||
/* The jump bar's sticky offset is set inline by JS; give it a sane default so a
|
||||
stale stylesheet can't park it behind the opaque header. */
|
||||
.section-nav-bar{position:sticky;top:48px;z-index:30;background:#fff;}
|
||||
/* F6/D3: the rail must not paint over the form before the real sheet lands,
|
||||
and a section must never be stuck collapsed if that sheet never arrives.
|
||||
Same reasoning as the panel above: this is a floor, not an override. */
|
||||
.sec-rail[hidden]{display:none;}
|
||||
.card.collapsed > .card-body[hidden]{display:none;}
|
||||
`;
|
||||
|
||||
function injectWpNavCriticalCss(){
|
||||
@@ -2757,9 +2980,6 @@ function initAutosave(){
|
||||
// the truth about. The bar is rendered by the app, so mount when it exists.
|
||||
const mountHost = document.querySelector('#sticky-save .sticky-status') || document.querySelector('#sticky-save');
|
||||
if(mountHost) WPAutosave.mountIndicator(mountHost);
|
||||
// Section changes are a "you have visibly moved on" moment, so flush rather than
|
||||
// wait out the debounce.
|
||||
document.querySelectorAll('.sec-chip').forEach(c=>c.addEventListener('click', ()=>WPAutosave.flush('section')));
|
||||
offerDraftRecovery();
|
||||
}
|
||||
|
||||
@@ -2935,6 +3155,12 @@ function bootData(){
|
||||
document.querySelectorAll('.main > .card, .main > .nav-row').forEach(e=>e.style.display='');
|
||||
syncToolTabs();
|
||||
}
|
||||
// F6/D3: which section you are in is state, so Back moves between sections
|
||||
// as well as between packages. fromUrl, because the URL already says this -
|
||||
// recording it again would make the first Back appear to do nothing.
|
||||
if(state.section && currentView !== 'Dashboard'){
|
||||
gotoSection(state.section, {fromUrl:true});
|
||||
}
|
||||
});
|
||||
}
|
||||
initAutosave();
|
||||
|
||||
Reference in New Issue
Block a user