|
1 | | -(function ($) { |
| 1 | +(function ($) { |
2 | 2 | $.widget("pic.controller", { |
3 | 3 | options: {}, |
4 | 4 | _create: function () { |
|
208 | 208 | row = $('<div class="picPanelMode" data-status="auto"><i class="far fa-pause-circle burst-animated"></i><label></label><span class="service-timeout-remaining"></span><i class="far fa-pause-circle burst-animated"></i></div>'); |
209 | 209 | row.appendTo(el); |
210 | 210 | $('<div class="picSpaDrain" data-status="off"><i class="fas fa-skull-crossbones burst-animated"></i><label>SPA DRAIN ACTIVE</label><i class="fas fa-skull-crossbones burst-animated"></i></div>').appendTo(el); |
| 211 | + // Keyboard + automation semantics for header icon controls. |
| 212 | + el.find('div.picModel > i, div.picConfigIcon, div.picLockIcon').attr('role', 'button').attr('tabindex', 0); |
| 213 | + el.find('div.picModel > i').attr('aria-label', 'Open Settings').attr('data-nav-id', 'settings-open'); |
| 214 | + el.find('div.picConfigIcon').attr('aria-label', 'Toggle Configuration View').attr('data-nav-id', 'config-toggle'); |
| 215 | + el.find('div.picLockIcon').attr('aria-label', 'Lock Or Unlock Settings').attr('data-nav-id', 'security-lock-toggle'); |
| 216 | + el.on('keydown', 'div.picModel > i, div.picConfigIcon, div.picLockIcon', function (evt) { |
| 217 | + if (evt.key === 'Enter' || evt.key === ' ' || evt.key === 'Spacebar') { |
| 218 | + evt.preventDefault(); |
| 219 | + $(evt.currentTarget).trigger('click'); |
| 220 | + } |
| 221 | + }); |
211 | 222 | el.find('div.picModel > i').on('click', function (evt) { |
212 | 223 | var btn = evt.currentTarget; |
213 | 224 | self._ensureAdminAccess(function () { |
214 | | - // Open up the settings window. |
| 225 | + // Toggle/reuse a single settings popover instance. |
| 226 | + if (o.settingsPopover && o.settingsPopover.length && o.settingsPopover.is(':visible')) { |
| 227 | + o.settingsPopover[0].close(); |
| 228 | + o.settingsPopover.remove(); |
| 229 | + o.settingsPopover = null; |
| 230 | + return; |
| 231 | + } |
| 232 | + // Cleanup any stale popovers left in DOM. |
| 233 | + el.parent().find('div.picPopover.picAppSettings').remove(); |
215 | 234 | var divPopover = $('<div class="picAppSettings"></div>'); |
| 235 | + o.settingsPopover = divPopover; |
216 | 236 | divPopover.appendTo(el.parent()); |
217 | 237 | divPopover.on('initPopover', function (e) { |
| 238 | + // Guard: initialize contents only once. |
| 239 | + if (divPopover.attr('data-settings-initialized') === 'true') return; |
| 240 | + divPopover.attr('data-settings-initialized', 'true'); |
218 | 241 | let divSettings = $('<div class="picAppSettings"></div>'); |
219 | 242 | divSettings.appendTo(e.contents()); |
220 | 243 | divSettings.settingsPanel(); |
221 | | - divSettings.on('loaded', function (e) { divPopover[0].show(btn); }); |
222 | 244 | e.stopImmediatePropagation(); |
223 | 245 | }); |
224 | | - divPopover.popover({ title: 'Settings', popoverStyle: 'modal', placement: { target: btn } }); |
| 246 | + divPopover.on('beforeClose', function () { |
| 247 | + o.settingsPopover = null; |
| 248 | + }); |
| 249 | + divPopover.popover({ |
| 250 | + title: 'Settings', |
| 251 | + popoverStyle: 'modal', |
| 252 | + autoClose: false, |
| 253 | + placement: { target: btn } |
| 254 | + }); |
225 | 255 | divPopover[0].show(btn); |
226 | 256 | }); |
227 | 257 | evt.preventDefault(); |
|
1467 | 1497 | var tabs = $('<div class="picTabPanel"></div>'); |
1468 | 1498 | console.log('Building controls'); |
1469 | 1499 | tabs.appendTo(el); |
| 1500 | + tabs.attr('id', 'settingsTabBar'); |
| 1501 | + tabs.attr('data-nav-group', 'settings-tabs'); |
1470 | 1502 | tabs.tabBar(); |
1471 | 1503 | $.getLocalService('/options', null, function (configData, status, xhr) { |
1472 | 1504 | console.log(configData); |
|
0 commit comments