Fossil SCM

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.

stephan 2020-08-11 15:26 trunk
Commit 33610b04de8fdf561a4b3cffed40353f008c87ed1d27a15f6b8c8731146265b4
2 files changed +14 -1 +32 -6
+14 -1
--- src/default.css
+++ src/default.css
@@ -970,14 +970,27 @@
970970
flex-direction: column;
971971
border-width: 1px;
972972
border-style: outset;
973973
border-color: inherit;
974974
}
975
-.tab-container > .tabs > .tab-panel {
975
+.tab-container > .tabs > .tab-panel,
976
+.tab-container > .tabs > fieldset.tab-wrapper {
977
+ align-self: stretch;
978
+ flex: 10 1 auto;
979
+ display: flex;
980
+ flex-direction: row;
981
+ border: 0;
982
+ padding: 0;
983
+ margin: 0;
984
+}
985
+.tab-container > .tabs > fieldset.tab-wrapper > .tab-panel{
976986
align-self: stretch;
977987
flex: 10 1 auto;
978988
display: block;
989
+ border: 0;
990
+ padding: 0;
991
+ margin: 0;
979992
}
980993
.tab-container > .tab-bar {
981994
display: flex;
982995
flex-direction: row;
983996
flex: 1 10 auto;
984997
--- src/default.css
+++ src/default.css
@@ -970,14 +970,27 @@
970 flex-direction: column;
971 border-width: 1px;
972 border-style: outset;
973 border-color: inherit;
974 }
975 .tab-container > .tabs > .tab-panel {
 
 
 
 
 
 
 
 
 
 
976 align-self: stretch;
977 flex: 10 1 auto;
978 display: block;
 
 
 
979 }
980 .tab-container > .tab-bar {
981 display: flex;
982 flex-direction: row;
983 flex: 1 10 auto;
984
--- src/default.css
+++ src/default.css
@@ -970,14 +970,27 @@
970 flex-direction: column;
971 border-width: 1px;
972 border-style: outset;
973 border-color: inherit;
974 }
975 .tab-container > .tabs > .tab-panel,
976 .tab-container > .tabs > fieldset.tab-wrapper {
977 align-self: stretch;
978 flex: 10 1 auto;
979 display: flex;
980 flex-direction: row;
981 border: 0;
982 padding: 0;
983 margin: 0;
984 }
985 .tab-container > .tabs > fieldset.tab-wrapper > .tab-panel{
986 align-self: stretch;
987 flex: 10 1 auto;
988 display: block;
989 border: 0;
990 padding: 0;
991 margin: 0;
992 }
993 .tab-container > .tab-bar {
994 display: flex;
995 flex-direction: row;
996 flex: 1 10 auto;
997
--- src/fossil.tabs.js
+++ src/fossil.tabs.js
@@ -12,37 +12,60 @@
1212
this.e = {};
1313
if(domElem) this.init(domElem);
1414
};
1515
1616
/**
17
- Internal helper to normalize a method argument
18
- to a tab element.
17
+ Internal helper to normalize a method argument to a tab
18
+ element. arg may be a tab DOM element or an index into
19
+ tabMgr.e.tabs.childNodes. Returns the corresponding tab element.
1920
*/
2021
const tabArg = function(arg,tabMgr){
2122
if('string'===typeof arg) arg = E(arg);
2223
else if(tabMgr && 'number'===typeof arg && arg>=0){
2324
arg = tabMgr.e.tabs.childNodes[arg];
25
+ }
26
+ if(arg){
27
+ if('FIELDSET'===arg.tagName && arg.classList.contains('tab-wrapper')){
28
+ arg = arg.firstElementChild;
29
+ }
2430
}
2531
return arg;
2632
};
2733
34
+
35
+ /**
36
+ Sets sets the visibility of tab element e to on or off. e MUST be
37
+ a TabManager tab element which has been wrapped in a
38
+ FIELDSET.tab-wrapper parent element. We disable the hidden
39
+ FIELDSET.tab-wrapper elements so that any access keys assigned
40
+ to their children cannot be inadvertently triggered
41
+ */
2842
const setVisible = function(e,yes){
29
- D[yes ? 'removeClass' : 'addClass'](e, 'hidden');
43
+ const fsWrapper = e.parentElement/*FIELDSET wrapper*/;
44
+ if(yes){
45
+ D.removeClass(e, 'hidden');
46
+ D.enable(fsWrapper);
47
+ }else{
48
+ D.addClass(e, 'hidden');
49
+ D.disable(fsWrapper);
50
+ }
3051
};
3152
3253
TabManager.prototype = {
3354
/**
3455
Initializes the tabs associated with the given tab container
3556
(DOM element or selector for a single element). This must be
3657
called once before using any other member functions of a given
3758
instance, noting that the constructor will call this if it is
38
- passed an argument.
59
+ passed an argument.
3960
4061
The tab container must have an 'id' attribute. This function
4162
looks through the DOM for all elements which have
4263
data-tab-parent=thatId. For each one it creates a button to
43
- switch to that tab and moves the element into this.e.tabs.
64
+ switch to that tab and moves the element into this.e.tabs,
65
+ *possibly* injecting an intermediary element between
66
+ this.e.tabs and the element.
4467
4568
The label for each tab is set by the data-tab-label attribute
4669
of each element, defaulting to something not terribly useful.
4770
4871
When it's done, it auto-selects the first tab unless a tab has
@@ -117,11 +140,13 @@
117140
e.target.$manager.switchToTab(e.target.$tab);
118141
};
119142
}
120143
tab = tabArg(tab);
121144
tab.remove();
122
- D.append(this.e.tabs, D.addClass(tab,'tab-panel'));
145
+ const eFs = D.addClass(D.fieldset(), 'tab-wrapper');
146
+ D.append(eFs, D.addClass(tab,'tab-panel'));
147
+ D.append(this.e.tabs, eFs);
123148
const lbl = tab.dataset.tabLabel || 'Tab #'+(this.e.tabs.childNodes.length-1);
124149
const btn = D.addClass(D.append(D.span(), lbl), 'tab-button');
125150
D.append(this.e.tabBar,btn);
126151
btn.$manager = this;
127152
btn.$tab = tab;
@@ -185,10 +210,11 @@
185210
this._dispatchEvent('before-switch-from', this._currentTab);
186211
}
187212
delete this._currentTab;
188213
this.e.tabs.childNodes.forEach((e,ndx)=>{
189214
const btn = this.e.tabBar.childNodes[ndx];
215
+ e = e.firstElementChild /* b/c arguments[0] is a FIELDSET wrapper */;
190216
if(e===tab){
191217
if(D.hasClass(e,'selected')){
192218
return;
193219
}
194220
self._dispatchEvent('before-switch-to',tab);
195221
--- src/fossil.tabs.js
+++ src/fossil.tabs.js
@@ -12,37 +12,60 @@
12 this.e = {};
13 if(domElem) this.init(domElem);
14 };
15
16 /**
17 Internal helper to normalize a method argument
18 to a tab element.
 
19 */
20 const tabArg = function(arg,tabMgr){
21 if('string'===typeof arg) arg = E(arg);
22 else if(tabMgr && 'number'===typeof arg && arg>=0){
23 arg = tabMgr.e.tabs.childNodes[arg];
 
 
 
 
 
24 }
25 return arg;
26 };
27
 
 
 
 
 
 
 
 
28 const setVisible = function(e,yes){
29 D[yes ? 'removeClass' : 'addClass'](e, 'hidden');
 
 
 
 
 
 
 
30 };
31
32 TabManager.prototype = {
33 /**
34 Initializes the tabs associated with the given tab container
35 (DOM element or selector for a single element). This must be
36 called once before using any other member functions of a given
37 instance, noting that the constructor will call this if it is
38 passed an argument.
39
40 The tab container must have an 'id' attribute. This function
41 looks through the DOM for all elements which have
42 data-tab-parent=thatId. For each one it creates a button to
43 switch to that tab and moves the element into this.e.tabs.
 
 
44
45 The label for each tab is set by the data-tab-label attribute
46 of each element, defaulting to something not terribly useful.
47
48 When it's done, it auto-selects the first tab unless a tab has
@@ -117,11 +140,13 @@
117 e.target.$manager.switchToTab(e.target.$tab);
118 };
119 }
120 tab = tabArg(tab);
121 tab.remove();
122 D.append(this.e.tabs, D.addClass(tab,'tab-panel'));
 
 
123 const lbl = tab.dataset.tabLabel || 'Tab #'+(this.e.tabs.childNodes.length-1);
124 const btn = D.addClass(D.append(D.span(), lbl), 'tab-button');
125 D.append(this.e.tabBar,btn);
126 btn.$manager = this;
127 btn.$tab = tab;
@@ -185,10 +210,11 @@
185 this._dispatchEvent('before-switch-from', this._currentTab);
186 }
187 delete this._currentTab;
188 this.e.tabs.childNodes.forEach((e,ndx)=>{
189 const btn = this.e.tabBar.childNodes[ndx];
 
190 if(e===tab){
191 if(D.hasClass(e,'selected')){
192 return;
193 }
194 self._dispatchEvent('before-switch-to',tab);
195
--- src/fossil.tabs.js
+++ src/fossil.tabs.js
@@ -12,37 +12,60 @@
12 this.e = {};
13 if(domElem) this.init(domElem);
14 };
15
16 /**
17 Internal helper to normalize a method argument to a tab
18 element. arg may be a tab DOM element or an index into
19 tabMgr.e.tabs.childNodes. Returns the corresponding tab element.
20 */
21 const tabArg = function(arg,tabMgr){
22 if('string'===typeof arg) arg = E(arg);
23 else if(tabMgr && 'number'===typeof arg && arg>=0){
24 arg = tabMgr.e.tabs.childNodes[arg];
25 }
26 if(arg){
27 if('FIELDSET'===arg.tagName && arg.classList.contains('tab-wrapper')){
28 arg = arg.firstElementChild;
29 }
30 }
31 return arg;
32 };
33
34
35 /**
36 Sets sets the visibility of tab element e to on or off. e MUST be
37 a TabManager tab element which has been wrapped in a
38 FIELDSET.tab-wrapper parent element. We disable the hidden
39 FIELDSET.tab-wrapper elements so that any access keys assigned
40 to their children cannot be inadvertently triggered
41 */
42 const setVisible = function(e,yes){
43 const fsWrapper = e.parentElement/*FIELDSET wrapper*/;
44 if(yes){
45 D.removeClass(e, 'hidden');
46 D.enable(fsWrapper);
47 }else{
48 D.addClass(e, 'hidden');
49 D.disable(fsWrapper);
50 }
51 };
52
53 TabManager.prototype = {
54 /**
55 Initializes the tabs associated with the given tab container
56 (DOM element or selector for a single element). This must be
57 called once before using any other member functions of a given
58 instance, noting that the constructor will call this if it is
59 passed an argument.
60
61 The tab container must have an 'id' attribute. This function
62 looks through the DOM for all elements which have
63 data-tab-parent=thatId. For each one it creates a button to
64 switch to that tab and moves the element into this.e.tabs,
65 *possibly* injecting an intermediary element between
66 this.e.tabs and the element.
67
68 The label for each tab is set by the data-tab-label attribute
69 of each element, defaulting to something not terribly useful.
70
71 When it's done, it auto-selects the first tab unless a tab has
@@ -117,11 +140,13 @@
140 e.target.$manager.switchToTab(e.target.$tab);
141 };
142 }
143 tab = tabArg(tab);
144 tab.remove();
145 const eFs = D.addClass(D.fieldset(), 'tab-wrapper');
146 D.append(eFs, D.addClass(tab,'tab-panel'));
147 D.append(this.e.tabs, eFs);
148 const lbl = tab.dataset.tabLabel || 'Tab #'+(this.e.tabs.childNodes.length-1);
149 const btn = D.addClass(D.append(D.span(), lbl), 'tab-button');
150 D.append(this.e.tabBar,btn);
151 btn.$manager = this;
152 btn.$tab = tab;
@@ -185,10 +210,11 @@
210 this._dispatchEvent('before-switch-from', this._currentTab);
211 }
212 delete this._currentTab;
213 this.e.tabs.childNodes.forEach((e,ndx)=>{
214 const btn = this.e.tabBar.childNodes[ndx];
215 e = e.firstElementChild /* b/c arguments[0] is a FIELDSET wrapper */;
216 if(e===tab){
217 if(D.hasClass(e,'selected')){
218 return;
219 }
220 self._dispatchEvent('before-switch-to',tab);
221

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button