Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | fossil.tabs API now injects a FIELDSET wrapper around all tabs so that we can disable all input elements on a tab by disabling the fieldset, the goal being to disable access to hotkeys which are mapped to elements which are in any tab other than the current one. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
33610b04de8fdf561a4b3cffed40353f |
User & Date: | stephan 2020-08-11 15:26:55 |
References
2020-08-16
| ||
10:05 | Reverted [33610b04de8fdf56] because a subtle bug in Chrome and FF causes both browsers to break scrolling of elements if they are descendants, however deeply nested, of a fieldset element. The one known workaround for that is too fragile. This is not release-critical. ... (Closed-Leaf check-in: e5c3ffeb user: stephan tags: post-2.12-fixes) | |
Context
2020-08-11
| ||
15:29 | fileedit confirmer buttons now use the new pinSize confirmer option. Minor style consistency tweak. fileedit no longer complains when discarding stashed edits when no file is loaded, and reloads the current file only if it was in the now-discarded local edits. ... (check-in: 83a95dbf user: stephan tags: trunk) | |
15:26 | fossil.tabs API now injects a FIELDSET wrapper around all tabs so that we can disable all input elements on a tab by disabling the fieldset, the goal being to disable access to hotkeys which are mapped to elements which are in any tab other than the current one. ... (check-in: 33610b04 user: stephan tags: trunk) | |
15:23 | Added fossil.confirmer pinSize option which tells it to try to pin the confirmation element's width to the maximum of its initial and awaiting-confirmation widths, to avoid layout reflow while awaiting confirmation. ... (check-in: b12cae85 user: stephan tags: trunk) | |
Changes
Changes to src/default.css.
︙ | ︙ | |||
968 969 970 971 972 973 974 | margin: 0; display: flex; flex-direction: column; border-width: 1px; border-style: outset; border-color: inherit; } | | > > > > > > > > > > > > > | 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 | margin: 0; display: flex; flex-direction: column; border-width: 1px; border-style: outset; border-color: inherit; } .tab-container > .tabs > .tab-panel, .tab-container > .tabs > fieldset.tab-wrapper { align-self: stretch; flex: 10 1 auto; display: flex; flex-direction: row; border: 0; padding: 0; margin: 0; } .tab-container > .tabs > fieldset.tab-wrapper > .tab-panel{ align-self: stretch; flex: 10 1 auto; display: block; border: 0; padding: 0; margin: 0; } .tab-container > .tab-bar { display: flex; flex-direction: row; flex: 1 10 auto; align-self: stretch; flex-wrap: wrap; |
︙ | ︙ |
Changes to src/fossil.tabs.js.
︙ | ︙ | |||
10 11 12 13 14 15 16 | */ const TabManager = function(domElem){ this.e = {}; if(domElem) this.init(domElem); }; /** | | | > > > > > > > > > > > > > > > > > > > | > > | | > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | */ const TabManager = function(domElem){ this.e = {}; if(domElem) this.init(domElem); }; /** Internal helper to normalize a method argument to a tab element. arg may be a tab DOM element or an index into tabMgr.e.tabs.childNodes. Returns the corresponding tab element. */ const tabArg = function(arg,tabMgr){ if('string'===typeof arg) arg = E(arg); else if(tabMgr && 'number'===typeof arg && arg>=0){ arg = tabMgr.e.tabs.childNodes[arg]; } if(arg){ if('FIELDSET'===arg.tagName && arg.classList.contains('tab-wrapper')){ arg = arg.firstElementChild; } } return arg; }; /** Sets sets the visibility of tab element e to on or off. e MUST be a TabManager tab element which has been wrapped in a FIELDSET.tab-wrapper parent element. We disable the hidden FIELDSET.tab-wrapper elements so that any access keys assigned to their children cannot be inadvertently triggered */ const setVisible = function(e,yes){ const fsWrapper = e.parentElement/*FIELDSET wrapper*/; if(yes){ D.removeClass(e, 'hidden'); D.enable(fsWrapper); }else{ D.addClass(e, 'hidden'); D.disable(fsWrapper); } }; TabManager.prototype = { /** Initializes the tabs associated with the given tab container (DOM element or selector for a single element). This must be called once before using any other member functions of a given instance, noting that the constructor will call this if it is passed an argument. The tab container must have an 'id' attribute. This function looks through the DOM for all elements which have data-tab-parent=thatId. For each one it creates a button to switch to that tab and moves the element into this.e.tabs, *possibly* injecting an intermediary element between this.e.tabs and the element. The label for each tab is set by the data-tab-label attribute of each element, defaulting to something not terribly useful. When it's done, it auto-selects the first tab unless a tab has a truthy numeric value in its data-tab-select attribute, in which case the last tab to have such a property is selected. |
︙ | ︙ | |||
115 116 117 118 119 120 121 | if(!f.click){ f.click = function(e){ e.target.$manager.switchToTab(e.target.$tab); }; } tab = tabArg(tab); tab.remove(); | > > | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | if(!f.click){ f.click = function(e){ e.target.$manager.switchToTab(e.target.$tab); }; } tab = tabArg(tab); tab.remove(); const eFs = D.addClass(D.fieldset(), 'tab-wrapper'); D.append(eFs, D.addClass(tab,'tab-panel')); D.append(this.e.tabs, eFs); const lbl = tab.dataset.tabLabel || 'Tab #'+(this.e.tabs.childNodes.length-1); const btn = D.addClass(D.append(D.span(), lbl), 'tab-button'); D.append(this.e.tabBar,btn); btn.$manager = this; btn.$tab = tab; btn.addEventListener('click', f.click, false); return this; |
︙ | ︙ | |||
183 184 185 186 187 188 189 190 191 192 193 194 195 196 | if(tab===this._currentTab) return this; else if(this._currentTab){ this._dispatchEvent('before-switch-from', this._currentTab); } delete this._currentTab; this.e.tabs.childNodes.forEach((e,ndx)=>{ const btn = this.e.tabBar.childNodes[ndx]; if(e===tab){ if(D.hasClass(e,'selected')){ return; } self._dispatchEvent('before-switch-to',tab); setVisible(e, true); this._currentTab = e; | > | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | if(tab===this._currentTab) return this; else if(this._currentTab){ this._dispatchEvent('before-switch-from', this._currentTab); } delete this._currentTab; this.e.tabs.childNodes.forEach((e,ndx)=>{ const btn = this.e.tabBar.childNodes[ndx]; e = e.firstElementChild /* b/c arguments[0] is a FIELDSET wrapper */; if(e===tab){ if(D.hasClass(e,'selected')){ return; } self._dispatchEvent('before-switch-to',tab); setVisible(e, true); this._currentTab = e; |
︙ | ︙ |