pixl-xyapp 2.1.6 → 2.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +23 -6
- package/README.md +2 -2
- package/css/base.css +47 -33
- package/js/base.js +55 -7
- package/js/calendar.js +2 -2
- package/js/datetime.js +2 -2
- package/js/dialog.js +32 -2
- package/js/page.js +19 -32
- package/js/popover.js +3 -0
- package/js/select.js +154 -60
- package/js/tools.js +3 -3
- package/package.json +3 -3
package/LICENSE.md
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
BSD 3-Clause License
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Copyright (c) 2019 - 2026 PixlCore LLC & CONTRIBUTORS.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
CHANGED
|
@@ -355,7 +355,7 @@ The pagination links work by constructing self-referencing URL to the current pa
|
|
|
355
355
|
|
|
356
356
|
Since the `limit` is set to 5 items per page, and `offset` starts at `0`, then the next page (page 2) will be at offset `5`. This link is simply a hashtag anchor tag, which doesn't reload the browser page, but will instead be caught by the navigation system, and call your page's `onDeactivate()` then its `onActivate()` with the new values. It is up to your page code to redraw the table with the new data chunk and new `offset` value.
|
|
357
357
|
|
|
358
|
-
Instead of generating hashtag anchor links, you can optionally provide a custom JavaScript function in a `pagination_link` property, which will be written into the HTML as an `
|
|
358
|
+
Instead of generating hashtag anchor links, you can optionally provide a custom JavaScript function in a `pagination_link` property, which will be written into the HTML as an `onClick` handler on each link, and called instead of a standard link. Note that it must be a string and globally accessible, so remember the `$P()` shortcut to get access to the current page. Example:
|
|
359
359
|
|
|
360
360
|
```javascript
|
|
361
361
|
pagination_link: '$P().tableNavClick'
|
|
@@ -370,7 +370,7 @@ Notification messages are shown in a fixed bar at the top of the screen, regardl
|
|
|
370
370
|
To use the notification system in your app, make sure this markup is in your main HTML page:
|
|
371
371
|
|
|
372
372
|
```html
|
|
373
|
-
<div id="d_message" class="message" style="display:none"
|
|
373
|
+
<div id="d_message" class="message" style="display:none" onClick="app.hideMessage(250)">
|
|
374
374
|
<div id="d_message_inner" class="message_inner"></div>
|
|
375
375
|
</div>
|
|
376
376
|
```
|
package/css/base.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* xyOps Base Theme */
|
|
2
|
-
/* Copyright (c) 2019 Joseph Huckaby -
|
|
2
|
+
/* Copyright (c) 2019 - 2026 Joseph Huckaby - BSD 3-Clause License */
|
|
3
3
|
|
|
4
4
|
* {
|
|
5
5
|
box-sizing: border-box;
|
|
@@ -112,22 +112,22 @@ body.dark {
|
|
|
112
112
|
--gray: rgb(98, 107, 115);
|
|
113
113
|
--gray-highlight: color-mix(in srgb, rgb(98, 107, 115) 80%, white);
|
|
114
114
|
|
|
115
|
-
--border-color: rgb(50,
|
|
115
|
+
--border-color: rgb(50, 50, 58);
|
|
116
116
|
--shadow-color: rgba(0, 0, 0, 0.0);
|
|
117
|
-
--background-color: rgb(24,
|
|
118
|
-
--header-background-color: rgb(32,
|
|
119
|
-
--header-text-color: rgb(125,
|
|
120
|
-
--box-background-color: rgb(32,
|
|
121
|
-
--form-background-color: rgb(40,
|
|
117
|
+
--background-color: rgb(24, 24, 32);
|
|
118
|
+
--header-background-color: rgb(32, 32, 38);
|
|
119
|
+
--header-text-color: rgb(125, 125, 150);
|
|
120
|
+
--box-background-color: rgb(32, 32, 38);
|
|
121
|
+
--form-background-color: rgb(40, 40, 48);
|
|
122
122
|
--table-header-background-color: rgba(200, 225, 255, 0.03);
|
|
123
123
|
|
|
124
|
-
--sidebar-background-color: rgb(32,
|
|
125
|
-
--sidebar-text-color: rgb(125,
|
|
124
|
+
--sidebar-background-color: rgb(32, 32, 38);
|
|
125
|
+
--sidebar-text-color: rgb(125, 125, 150);
|
|
126
126
|
|
|
127
|
-
--body-text-color: rgb(170,
|
|
128
|
-
--link-color: rgb(145,
|
|
129
|
-
--label-color: rgb(145,
|
|
130
|
-
--alt-label-color: rgb(120,
|
|
127
|
+
--body-text-color: rgb(170, 170, 200);
|
|
128
|
+
--link-color: rgb(145, 145, 170);
|
|
129
|
+
--label-color: rgb(145, 145, 170);
|
|
130
|
+
--alt-label-color: rgb(120, 120, 130);
|
|
131
131
|
--icon-color: rgb(115, 115, 130);
|
|
132
132
|
--icon-color-half: rgba(115, 115, 130, 0.5);
|
|
133
133
|
}
|
|
@@ -178,6 +178,14 @@ body.dark fieldset input {
|
|
|
178
178
|
background: var(--box-background-color);
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
button.link {
|
|
182
|
+
background: none;
|
|
183
|
+
border: none;
|
|
184
|
+
padding: 0;
|
|
185
|
+
margin: 0;
|
|
186
|
+
font: inherit;
|
|
187
|
+
}
|
|
188
|
+
|
|
181
189
|
a, .link {
|
|
182
190
|
color: var(--link-color);
|
|
183
191
|
}
|
|
@@ -197,6 +205,12 @@ a, .link {
|
|
|
197
205
|
text-decoration: none;
|
|
198
206
|
}
|
|
199
207
|
|
|
208
|
+
.link {
|
|
209
|
+
user-select: none;
|
|
210
|
+
-moz-user-select: none;
|
|
211
|
+
-webkit-user-select: none;
|
|
212
|
+
}
|
|
213
|
+
|
|
200
214
|
a.danger:hover, .link.danger:hover {
|
|
201
215
|
color: var(--red) !important;
|
|
202
216
|
}
|
|
@@ -695,17 +709,12 @@ div.toast > span {
|
|
|
695
709
|
word-break: break-word;
|
|
696
710
|
}
|
|
697
711
|
|
|
698
|
-
div.toast.success { background:
|
|
699
|
-
div.toast.warning { background:
|
|
712
|
+
div.toast.success { background: var(--green); }
|
|
713
|
+
div.toast.warning { background: var(--yellow); }
|
|
700
714
|
div.toast.error { background: var(--red); }
|
|
701
|
-
div.toast.critical { background:
|
|
702
|
-
div.toast.info { background:
|
|
703
|
-
|
|
704
|
-
body.dark div.toast.success { background: rgb(20, 128, 20); }
|
|
705
|
-
body.dark div.toast.warning { background: rgb(128, 128, 20); }
|
|
706
|
-
body.dark div.toast.error { background-color:var(--red); }
|
|
707
|
-
body.dark div.toast.critical { background: rgb(128, 20, 128); }
|
|
708
|
-
body.dark div.toast.info { background: rgb(28, 84, 160); }
|
|
715
|
+
div.toast.critical { background: var(--purple); }
|
|
716
|
+
div.toast.info { background: var(--theme-color); }
|
|
717
|
+
div.toast.suspended { background: var(--orange); }
|
|
709
718
|
|
|
710
719
|
div.toast.channel {
|
|
711
720
|
background: var(--box-background-color);
|
|
@@ -787,6 +796,7 @@ div.message.error { background: var(--red); }
|
|
|
787
796
|
div.message.critical { background: var(--purple); }
|
|
788
797
|
div.message.abort { background: var(--red); }
|
|
789
798
|
div.message.info { background: var(--blue); }
|
|
799
|
+
div.message.suspended { background: var(--orange); }
|
|
790
800
|
|
|
791
801
|
/* body.dark div.message.success { background: rgb(20, 128, 20); }
|
|
792
802
|
body.dark div.message.warning { background: rgb(128, 128, 20); }
|
|
@@ -1494,9 +1504,6 @@ body.dark fieldset .checkbox_container > label:before {
|
|
|
1494
1504
|
transform: scale(.2);
|
|
1495
1505
|
}
|
|
1496
1506
|
|
|
1497
|
-
/* .checkbox_container > input:hover ~ label:before {
|
|
1498
|
-
border-color: var(--theme-color);
|
|
1499
|
-
} */
|
|
1500
1507
|
.checkbox_container > input:hover ~ label {
|
|
1501
1508
|
color: var(--theme-color);
|
|
1502
1509
|
}
|
|
@@ -1521,13 +1528,11 @@ body.dark fieldset .checkbox_container > label:before {
|
|
|
1521
1528
|
.checkbox_container:hover {
|
|
1522
1529
|
color: var(--body-text-color);
|
|
1523
1530
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
background-color: var(--theme-color-half) !important;
|
|
1530
|
-
} */
|
|
1531
|
+
|
|
1532
|
+
.checkbox_container > input:focus-visible ~ label::before {
|
|
1533
|
+
outline: 2px solid var(--theme-color);
|
|
1534
|
+
outline-offset: 2px;
|
|
1535
|
+
}
|
|
1531
1536
|
|
|
1532
1537
|
div.info_label {
|
|
1533
1538
|
font-size: 11px;
|
|
@@ -1911,6 +1916,10 @@ div.progress_bar_label.second_half {
|
|
|
1911
1916
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4);
|
|
1912
1917
|
}
|
|
1913
1918
|
|
|
1919
|
+
.progress_bar_label i.mdi:before {
|
|
1920
|
+
transform: scale(1.5);
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1914
1923
|
div.progress_bar_container.indeterminate div.progress_bar_label {
|
|
1915
1924
|
display: none;
|
|
1916
1925
|
}
|
|
@@ -2398,6 +2407,7 @@ table.data_table.compact th:first-child, table.data_table.compact td:first-child
|
|
|
2398
2407
|
}
|
|
2399
2408
|
|
|
2400
2409
|
div.data_table_compact > div.data_grid > ul.grid_row_header > div {
|
|
2410
|
+
border-top: none;
|
|
2401
2411
|
margin-bottom: 5px;
|
|
2402
2412
|
}
|
|
2403
2413
|
|
|
@@ -2587,6 +2597,10 @@ body.dark .data_grid > ul.grid_row_header > div {
|
|
|
2587
2597
|
padding-right: 1px;
|
|
2588
2598
|
}
|
|
2589
2599
|
|
|
2600
|
+
.data_grid > ul > div .progress_bar_container {
|
|
2601
|
+
margin: 1px 0 2px 0; /* Nudge height from 18px to 21px to match std grid units */
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2590
2604
|
.data_grid ul.disabled div {
|
|
2591
2605
|
opacity: 0.6;
|
|
2592
2606
|
}
|
package/js/base.js
CHANGED
|
@@ -41,7 +41,7 @@ var app = {
|
|
|
41
41
|
|
|
42
42
|
setHeaderNav: function(items) {
|
|
43
43
|
// populate header with multiple nav elements
|
|
44
|
-
var html = '<div class="header_nav_cont">';
|
|
44
|
+
var html = '<div class="header_nav_cont" role="navigation">';
|
|
45
45
|
|
|
46
46
|
items.forEach( function(item, idx) {
|
|
47
47
|
if (!item) return;
|
|
@@ -225,9 +225,11 @@ var app = {
|
|
|
225
225
|
var icon = '';
|
|
226
226
|
switch (type) {
|
|
227
227
|
case 'success': icon = 'check-circle'; break;
|
|
228
|
-
case 'warning': icon = 'alert-
|
|
228
|
+
case 'warning': icon = 'alert-rhombus'; break;
|
|
229
229
|
case 'error': icon = 'alert-decagram'; break;
|
|
230
230
|
case 'info': icon = 'information-outline'; break;
|
|
231
|
+
case 'critical': icon = 'fire-alert'; break;
|
|
232
|
+
case 'suspended': icon = 'motion-pause-outline'; break;
|
|
231
233
|
|
|
232
234
|
default:
|
|
233
235
|
if (type.match(/^(\w+)\/(.+)$/)) { type = RegExp.$1; icon = RegExp.$2; }
|
|
@@ -245,8 +247,11 @@ var app = {
|
|
|
245
247
|
// show toast notification given raw html
|
|
246
248
|
var { type, icon, msg, lifetime, loc } = args;
|
|
247
249
|
|
|
250
|
+
var role = 'alert';
|
|
251
|
+
if ((type == 'success') || (type == 'info')) role = 'status';
|
|
252
|
+
|
|
248
253
|
var html = '';
|
|
249
|
-
html += '<div class="toast ' + type + '" style="display:none">';
|
|
254
|
+
html += '<div class="toast ' + type + '" style="display:none" role="' + role + '" aria-atomic="true">';
|
|
250
255
|
html += '<i class="mdi mdi-' + icon + '"></i>';
|
|
251
256
|
html += '<span>' + msg + '</span>';
|
|
252
257
|
html += '</div>';
|
|
@@ -259,7 +264,11 @@ var app = {
|
|
|
259
264
|
$toast.on('click', function() {
|
|
260
265
|
if (timer) clearTimeout(timer);
|
|
261
266
|
$toast.fadeOut( 250, function() { $(this).remove(); } );
|
|
262
|
-
if (loc)
|
|
267
|
+
if (loc) {
|
|
268
|
+
$toast.addClass('clicky');
|
|
269
|
+
if (typeof(loc) == 'function') loc();
|
|
270
|
+
else if (typeof(loc) == 'string') Nav.go(loc);
|
|
271
|
+
}
|
|
263
272
|
} );
|
|
264
273
|
|
|
265
274
|
if ((type == 'success') || (type == 'info') || lifetime) {
|
|
@@ -271,9 +280,7 @@ var app = {
|
|
|
271
280
|
},
|
|
272
281
|
|
|
273
282
|
hideMessage: function(animate) {
|
|
274
|
-
//
|
|
275
|
-
// else $('#d_message').hide();
|
|
276
|
-
|
|
283
|
+
// hide all toasts
|
|
277
284
|
if (animate) $('div.toast').fadeOut( animate, function() { $(this).remove(); } );
|
|
278
285
|
else $('div.toast').remove();
|
|
279
286
|
},
|
|
@@ -532,6 +539,47 @@ var app = {
|
|
|
532
539
|
notifyUserNav: function(loc) {
|
|
533
540
|
// override in app
|
|
534
541
|
// called by each page nav operation
|
|
542
|
+
},
|
|
543
|
+
|
|
544
|
+
focusNext($cur, $cont) {
|
|
545
|
+
// focus the next focusable element
|
|
546
|
+
if (!$cur) $cur = $(document.activeElement);
|
|
547
|
+
if (!$cont) $cont = $(document);
|
|
548
|
+
|
|
549
|
+
const $elems = $cont.find(
|
|
550
|
+
'a[href], button, input, textarea, select, details, summary, [tabindex]:not([tabindex="-1"])'
|
|
551
|
+
).filter(function() {
|
|
552
|
+
const $el = $(this);
|
|
553
|
+
if ($el.is(':disabled') || !$el.is(':visible')) return false;
|
|
554
|
+
if ($el.attr('tabindex') === "-1") return false;
|
|
555
|
+
return true;
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// Find current element in list
|
|
559
|
+
const idx = $elems.index($cur);
|
|
560
|
+
|
|
561
|
+
// Focus the next tabbable element
|
|
562
|
+
if (idx !== -1 && idx < $elems.length - 1) {
|
|
563
|
+
const $next = $elems.eq(idx + 1);
|
|
564
|
+
$next.focus();
|
|
565
|
+
return $next;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
return null;
|
|
569
|
+
},
|
|
570
|
+
|
|
571
|
+
buttonize: function($sel) {
|
|
572
|
+
// add aria roles and keyboard handlers to all buttons inside container
|
|
573
|
+
$sel.find('.button').attr({ role: 'button', tabindex: '0', onkeypress: 'app.buttonKey(this,event)' });
|
|
574
|
+
},
|
|
575
|
+
|
|
576
|
+
buttonKey: function(elem, event) {
|
|
577
|
+
// key pressed while button is focused -- click if space or enter
|
|
578
|
+
if ((event.key == 'Enter') || (event.key == ' ')) {
|
|
579
|
+
event.preventDefault();
|
|
580
|
+
event.stopPropagation();
|
|
581
|
+
$(elem).click();
|
|
582
|
+
}
|
|
535
583
|
}
|
|
536
584
|
|
|
537
585
|
}; // app object
|
package/js/calendar.js
CHANGED
|
@@ -46,9 +46,9 @@ var Calendar = {
|
|
|
46
46
|
|
|
47
47
|
html += '<div class="calendar">';
|
|
48
48
|
html += '<div class="cal_header">';
|
|
49
|
-
html += '<div class="ch_nav ch_prev"
|
|
49
|
+
html += '<div class="ch_nav ch_prev" onClick="Calendar.prevMonth()" title="Previous Month"><i class="mdi mdi-chevron-double-left"></i></div>';
|
|
50
50
|
html += '<div class="ch_title"></div>';
|
|
51
|
-
html += '<div class="ch_nav ch_next"
|
|
51
|
+
html += '<div class="ch_nav ch_next" onClick="Calendar.nextMonth()" title="Next Month"><i class="mdi mdi-chevron-double-right"></i></div>';
|
|
52
52
|
html += '</div>';
|
|
53
53
|
html += '<div class="cal_days">';
|
|
54
54
|
_short_day_names.forEach( function(ddd) {
|
package/js/datetime.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Joe's Date/Time Tools
|
|
2
|
-
// Copyright (c) 2004 -
|
|
3
|
-
// Released under the
|
|
2
|
+
// Copyright (c) 2004 - 2026 Joseph Huckaby
|
|
3
|
+
// Released under the BSD 3-Clause License
|
|
4
4
|
|
|
5
5
|
var _months = [
|
|
6
6
|
[ 1, 'January' ], [ 2, 'February' ], [ 3, 'March' ], [ 4, 'April' ],
|
package/js/dialog.js
CHANGED
|
@@ -45,7 +45,7 @@ var Dialog = {
|
|
|
45
45
|
$('#dialog').stop().remove();
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
var $dialog = $('<div id="dialog" class="dialog"></div>').css({
|
|
48
|
+
var $dialog = $('<div id="dialog" class="dialog" role="dialog" aria-modal="true"></div>').css({
|
|
49
49
|
opacity: 0,
|
|
50
50
|
left: '' + x + 'px',
|
|
51
51
|
top: '' + y + 'px'
|
|
@@ -56,6 +56,12 @@ var Dialog = {
|
|
|
56
56
|
|
|
57
57
|
this.active = true;
|
|
58
58
|
unscroll();
|
|
59
|
+
|
|
60
|
+
// buttonize all buttons
|
|
61
|
+
app.buttonize( $dialog );
|
|
62
|
+
|
|
63
|
+
// make everything behind us inert, for accessibility
|
|
64
|
+
$('div.sidebar, div.header, div.main, div.footer').attr('inert', 'true');
|
|
59
65
|
},
|
|
60
66
|
|
|
61
67
|
autoResize: function() {
|
|
@@ -83,6 +89,7 @@ var Dialog = {
|
|
|
83
89
|
if (this.active) {
|
|
84
90
|
$('#dialog').stop().fadeOut( 250, function() { $(this).remove(); } );
|
|
85
91
|
$('#dialog_overlay').stop().fadeOut( 300, function() { $(this).remove(); } );
|
|
92
|
+
$('div.sidebar, div.header, div.main, div.footer').removeAttr('inert');
|
|
86
93
|
this.active = false;
|
|
87
94
|
unscroll.reset();
|
|
88
95
|
|
|
@@ -221,6 +228,9 @@ var Dialog = {
|
|
|
221
228
|
Dialog.active = 'confirmation';
|
|
222
229
|
|
|
223
230
|
setTimeout( function() {
|
|
231
|
+
// change aria role for danger type
|
|
232
|
+
$('#dialog').attr('role', 'alertdialog');
|
|
233
|
+
|
|
224
234
|
// hold alt/opt key to immediately click default button
|
|
225
235
|
if (app.lastClick.altKey) return Dialog.confirm_click(true);
|
|
226
236
|
}, 1 );
|
|
@@ -300,7 +310,7 @@ var CodeEditor = {
|
|
|
300
310
|
$('#ceditor').stop().remove();
|
|
301
311
|
}
|
|
302
312
|
|
|
303
|
-
var $dialog = $('<div class="dialog" id="ceditor"></div>').css({
|
|
313
|
+
var $dialog = $('<div class="dialog" id="ceditor" role="dialog" aria-modal="true"></div>').css({
|
|
304
314
|
opacity: 0,
|
|
305
315
|
left: '' + x + 'px',
|
|
306
316
|
top: '' + y + 'px'
|
|
@@ -313,6 +323,17 @@ var CodeEditor = {
|
|
|
313
323
|
|
|
314
324
|
// only do the unscroll thing if another dialog isn't active under us
|
|
315
325
|
if (!Dialog.active) unscroll();
|
|
326
|
+
|
|
327
|
+
// if dialog is active under us, remove its modal role and make it inert
|
|
328
|
+
if (Dialog.active) {
|
|
329
|
+
$('#dialog').removeAttr('aria-modal').attr({ 'aria-hidden': 'true', 'inert': 'true' });
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
$('div.sidebar, div.header, div.main, div.footer').attr('inert', 'true');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// buttonize all buttons
|
|
336
|
+
app.buttonize( $dialog );
|
|
316
337
|
},
|
|
317
338
|
|
|
318
339
|
autoResize: function() {
|
|
@@ -345,6 +366,14 @@ var CodeEditor = {
|
|
|
345
366
|
// only release scroll lock if another dialog isn't active under us
|
|
346
367
|
if (!Dialog.active) unscroll.reset();
|
|
347
368
|
|
|
369
|
+
// if dialog is active under us, restore its modal role
|
|
370
|
+
if (Dialog.active) {
|
|
371
|
+
$('#dialog').attr('aria-modal', 'true').removeAttr('aria-hidden').removeAttr('inert');
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
$('div.sidebar, div.header, div.main, div.footer').removeAttr('inert');
|
|
375
|
+
}
|
|
376
|
+
|
|
348
377
|
if (this.onHide) {
|
|
349
378
|
// one time hook for hide
|
|
350
379
|
var callback = this.onHide;
|
|
@@ -353,6 +382,7 @@ var CodeEditor = {
|
|
|
353
382
|
}
|
|
354
383
|
|
|
355
384
|
this.onDragDrop = null;
|
|
385
|
+
this.onKeyDown = null;
|
|
356
386
|
}
|
|
357
387
|
},
|
|
358
388
|
|
package/js/page.js
CHANGED
|
@@ -88,7 +88,7 @@ window.Page = class Page {
|
|
|
88
88
|
|
|
89
89
|
html += '<div class="form_row ' + extra_classes + '" ' + compose_attribs(args) + '>';
|
|
90
90
|
if (label) html += '<div class="fr_label">' + label + '</div>';
|
|
91
|
-
if (content) html += '<div class="fr_content">' + content + '</div>';
|
|
91
|
+
if (content) html += '<div class="fr_content" aria-label="' + strip_html(label).replace(/\&\w+\;/g, '').trim() + '">' + content + '</div>';
|
|
92
92
|
if (suffix) html += '<div class="fr_suffix">' + suffix + '</div>';
|
|
93
93
|
if (caption) html += '<div class="fr_caption"><span>' + inline_marked(caption) + '</span></div>'; // markdown
|
|
94
94
|
html += '</div>';
|
|
@@ -161,7 +161,7 @@ window.Page = class Page {
|
|
|
161
161
|
|
|
162
162
|
html += '<div class="checkbox_container">';
|
|
163
163
|
html += '<input type="checkbox" ' + compose_attribs(args) + '/>';
|
|
164
|
-
html += '<label>' + label + '</label>';
|
|
164
|
+
html += '<label for="' + (args.id || '') + '">' + label + '</label>';
|
|
165
165
|
html += '</div>';
|
|
166
166
|
|
|
167
167
|
return html;
|
|
@@ -557,7 +557,7 @@ window.Page = class Page {
|
|
|
557
557
|
// html += 'Page: ';
|
|
558
558
|
if (current_page > 1) {
|
|
559
559
|
if (cpl) {
|
|
560
|
-
html += '<span class="link"
|
|
560
|
+
html += '<span class="link" onClick="'+cpl+'('+Math.floor((current_page - 2) * results.limit)+')">« Prev</span>';
|
|
561
561
|
}
|
|
562
562
|
else {
|
|
563
563
|
html += '<a href="#' + this.ID + compose_query_string(merge_objects(this.args, {
|
|
@@ -587,7 +587,7 @@ window.Page = class Page {
|
|
|
587
587
|
}
|
|
588
588
|
else {
|
|
589
589
|
if (cpl) {
|
|
590
|
-
html += '<span class="link"
|
|
590
|
+
html += '<span class="link" onClick="'+cpl+'('+Math.floor((idx - 1) * results.limit)+')">' + commify(idx) + '</span>';
|
|
591
591
|
}
|
|
592
592
|
else {
|
|
593
593
|
html += '<a href="#' + this.ID + compose_query_string(merge_objects(this.args, {
|
|
@@ -601,7 +601,7 @@ window.Page = class Page {
|
|
|
601
601
|
html += ' ';
|
|
602
602
|
if (current_page < num_pages) {
|
|
603
603
|
if (cpl) {
|
|
604
|
-
html += '<span class="link"
|
|
604
|
+
html += '<span class="link" onClick="'+cpl+'('+Math.floor((current_page + 0) * results.limit)+')">Next »</span>';
|
|
605
605
|
}
|
|
606
606
|
else {
|
|
607
607
|
html += '<a href="#' + this.ID + compose_query_string(merge_objects(this.args, {
|
|
@@ -717,7 +717,7 @@ window.Page = class Page {
|
|
|
717
717
|
// html += 'Page: ';
|
|
718
718
|
if (current_page > 1) {
|
|
719
719
|
if (cpl) {
|
|
720
|
-
html += '<span class="link"
|
|
720
|
+
html += '<span class="link" onClick="'+cpl+'('+Math.floor((current_page - 2) * results.limit)+')">« Prev</span>';
|
|
721
721
|
}
|
|
722
722
|
else {
|
|
723
723
|
html += '<a href="#' + this.ID + compose_query_string(merge_objects(this.args, {
|
|
@@ -748,7 +748,7 @@ window.Page = class Page {
|
|
|
748
748
|
}
|
|
749
749
|
else {
|
|
750
750
|
if (cpl) {
|
|
751
|
-
html += '<span class="link"
|
|
751
|
+
html += '<span class="link" onClick="'+cpl+'('+Math.floor((idx - 1) * results.limit)+')">' + commify(idx) + '</span>';
|
|
752
752
|
}
|
|
753
753
|
else {
|
|
754
754
|
html += '<a href="#' + this.ID + compose_query_string(merge_objects(this.args, {
|
|
@@ -763,7 +763,7 @@ window.Page = class Page {
|
|
|
763
763
|
|
|
764
764
|
if (current_page < num_pages) {
|
|
765
765
|
if (cpl) {
|
|
766
|
-
html += '<span class="link"
|
|
766
|
+
html += '<span class="link" onClick="'+cpl+'('+Math.floor((current_page + 0) * results.limit)+')">Next »</span>';
|
|
767
767
|
}
|
|
768
768
|
else {
|
|
769
769
|
html += '<a href="#' + this.ID + compose_query_string(merge_objects(this.args, {
|
|
@@ -1250,26 +1250,17 @@ window.Page = class Page {
|
|
|
1250
1250
|
var $elem = $field.closest('.form_row').find('.fr_suffix .checker');
|
|
1251
1251
|
|
|
1252
1252
|
if (username.match(/^[\w\-\.]+$/)) {
|
|
1253
|
-
// check with
|
|
1254
|
-
app.
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
$elem.css('color', 'red').html('<span class="mdi mdi-alert-decagram"></span>').attr('title', "Username is malformed.");
|
|
1265
|
-
$field.addClass('warning');
|
|
1266
|
-
}
|
|
1267
|
-
else {
|
|
1268
|
-
// username is valid and available!
|
|
1269
|
-
$elem.css('color','green').html('<span class="mdi mdi-check-circle"></span>').attr('title', "Username available!");
|
|
1270
|
-
$field.removeClass('warning');
|
|
1271
|
-
}
|
|
1272
|
-
} );
|
|
1253
|
+
// check with user list
|
|
1254
|
+
if (find_object( app.users, { username })) {
|
|
1255
|
+
// username taken
|
|
1256
|
+
$elem.css('color','red').html('<span class="mdi mdi-alert-circle"></span>').attr('title', "Username is taken.");
|
|
1257
|
+
$field.addClass('warning');
|
|
1258
|
+
}
|
|
1259
|
+
else {
|
|
1260
|
+
// username is valid and available!
|
|
1261
|
+
$elem.css('color','green').html('<span class="mdi mdi-check-circle"></span>').attr('title', "Username available!");
|
|
1262
|
+
$field.removeClass('warning');
|
|
1263
|
+
}
|
|
1273
1264
|
}
|
|
1274
1265
|
else if (username.length) {
|
|
1275
1266
|
// bad username
|
|
@@ -1726,10 +1717,6 @@ window.PageManager = class PageManager {
|
|
|
1726
1717
|
var result = page.onActivate.apply(page, [args]);
|
|
1727
1718
|
if (typeof(result) == 'boolean') return result;
|
|
1728
1719
|
else throw("Page " + id + " onActivate did not return a boolean!");
|
|
1729
|
-
|
|
1730
|
-
// expand section if applicable -- TODO: unreachable code:
|
|
1731
|
-
var $sect = $('#tab_'+id).parent().prev();
|
|
1732
|
-
if ($sect.length && $sect.hasClass('section_title')) this.expandSidebarGroup( $sect );
|
|
1733
1720
|
}
|
|
1734
1721
|
|
|
1735
1722
|
deactivate(id, new_id) {
|
package/js/popover.js
CHANGED
package/js/select.js
CHANGED
|
@@ -9,9 +9,9 @@ var SingleSelect = {
|
|
|
9
9
|
$(sel).each( function() {
|
|
10
10
|
var self = this;
|
|
11
11
|
var $this = $(this);
|
|
12
|
-
$this.css('display', 'none');
|
|
12
|
+
$this.css('display', 'none').attr({ 'aria-hidden': true, tabindex: '-1' });
|
|
13
13
|
|
|
14
|
-
var $ms = $('<div class="multiselect single"></div>');
|
|
14
|
+
var $ms = $('<div class="multiselect single" role="button" tabindex="0" aria-haspopup="listbox" aria-expanded="false"></div>');
|
|
15
15
|
if ($this.data('private')) $ms.attr('data-private', 1);
|
|
16
16
|
$this.after( $ms );
|
|
17
17
|
|
|
@@ -50,16 +50,25 @@ var SingleSelect = {
|
|
|
50
50
|
// also expose redraw as a custom event that can be triggered
|
|
51
51
|
$this.on('redraw', redraw);
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
// allow keyboard to open menu
|
|
54
|
+
$ms.on('keydown', function(event) {
|
|
55
|
+
if ((event.key == 'Enter') || (event.key == ' ')) {
|
|
56
|
+
$ms.click();
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
}
|
|
59
|
+
} );
|
|
60
|
+
|
|
61
|
+
$ms.on('click', function() {
|
|
54
62
|
// create popover dialog for selecting and filtering
|
|
55
63
|
var html = '';
|
|
56
64
|
var is_private = $this.data('private');
|
|
57
65
|
if ($ms.hasClass('disabled')) return;
|
|
66
|
+
$ms.attr('aria-expanded', 'true');
|
|
58
67
|
|
|
59
68
|
html += '<div class="sel_dialog_label">' + ($this.attr('title') || 'Select Item') + '</div>';
|
|
60
69
|
|
|
61
70
|
if (!$this.data('compact')) {
|
|
62
|
-
html += '<div class="sel_dialog_search_container">';
|
|
71
|
+
html += '<div class="sel_dialog_search_container" role="search">';
|
|
63
72
|
html += '<input type="text" id="fe_sel_dialog_search" class="sel_dialog_search" autocomplete="off" value=""/>';
|
|
64
73
|
html += '<div class="sel_dialog_search_icon"><i class="mdi mdi-magnify"></i></div>';
|
|
65
74
|
html += '</div>';
|
|
@@ -67,7 +76,7 @@ var SingleSelect = {
|
|
|
67
76
|
|
|
68
77
|
html += '<div id="d_sel_dialog_scrollarea" class="sel_dialog_scrollarea';
|
|
69
78
|
if ($this.data('nudgeheight')) html += ' nudgeheight';
|
|
70
|
-
html += '">';
|
|
79
|
+
html += '" role="listbox">';
|
|
71
80
|
|
|
72
81
|
for (var idx = 0, len = self.options.length; idx < len; idx++) {
|
|
73
82
|
var opt = self.options[idx];
|
|
@@ -83,7 +92,8 @@ var SingleSelect = {
|
|
|
83
92
|
}
|
|
84
93
|
if ($this.data('shrinkwrap')) html += ' shrinkwrap';
|
|
85
94
|
|
|
86
|
-
html += '" ' + ((idx >= SingleSelect.maxMenuItems) ? 'style="display:none"' : '') + ' data-value="' + opt.value + '"
|
|
95
|
+
html += '" ' + ((idx >= SingleSelect.maxMenuItems) ? 'style="display:none"' : '') + ' data-value="' + opt.value + '"';
|
|
96
|
+
html += ' role="option" aria-selected="' + (opt.selected ? 'true' : 'false') + '" tabindex="-1">';
|
|
87
97
|
|
|
88
98
|
if (opt.getAttribute && opt.getAttribute('data-icon')) {
|
|
89
99
|
html += '<i class="mdi mdi-' + opt.getAttribute('data-icon') + '"> </i>';
|
|
@@ -100,11 +110,11 @@ var SingleSelect = {
|
|
|
100
110
|
}
|
|
101
111
|
html += '</div>';
|
|
102
112
|
|
|
103
|
-
html += '</div>';
|
|
113
|
+
html += '</div>'; // scrollarea
|
|
104
114
|
|
|
105
115
|
Popover.attach( $ms, '<div style="padding:15px;">' + html + '</div>', $this.data('shrinkwrap') || false );
|
|
106
116
|
|
|
107
|
-
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').on('
|
|
117
|
+
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').on('click', function() {
|
|
108
118
|
// select item, close dialog and update multi-select
|
|
109
119
|
var $item = $(this);
|
|
110
120
|
$this.val( $item.data('value') );
|
|
@@ -154,19 +164,64 @@ var SingleSelect = {
|
|
|
154
164
|
if ((event.keyCode == 13) && value.length) {
|
|
155
165
|
event.preventDefault();
|
|
156
166
|
event.stopPropagation();
|
|
157
|
-
$('#d_sel_dialog_scrollarea > div.sel_dialog_item.match').slice(0, 1).trigger('
|
|
167
|
+
$('#d_sel_dialog_scrollarea > div.sel_dialog_item.match').slice(0, 1).trigger('click');
|
|
158
168
|
}
|
|
159
169
|
});
|
|
160
170
|
}
|
|
161
171
|
|
|
172
|
+
// handle keyboard focus
|
|
173
|
+
Popover.onKeyDown = SingleSelect.handleKeyDown;
|
|
174
|
+
|
|
162
175
|
// highlight select field under us
|
|
163
176
|
$ms.addClass('selected');
|
|
164
|
-
Popover.onDetach = function() {
|
|
165
|
-
|
|
177
|
+
Popover.onDetach = function() {
|
|
178
|
+
$ms.removeClass('selected').attr('aria-expanded', 'false').focus();
|
|
179
|
+
};
|
|
180
|
+
}); // click
|
|
166
181
|
|
|
167
182
|
}); // forach elem
|
|
168
183
|
},
|
|
169
184
|
|
|
185
|
+
handleKeyDown: function(event) {
|
|
186
|
+
var $options = $('#d_sel_dialog_scrollarea > div.sel_dialog_item');
|
|
187
|
+
var $active = $(document.activeElement).closest('.sel_dialog_item');
|
|
188
|
+
|
|
189
|
+
var focusItem = function($item) {
|
|
190
|
+
if (!$item.length) return;
|
|
191
|
+
$options.attr({ 'tabindex':'-1', 'aria-selected':'false' });
|
|
192
|
+
$item.attr({ 'tabindex':'0', 'aria-selected':'true' }).focus();
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
switch (event.key) {
|
|
196
|
+
case 'ArrowDown':
|
|
197
|
+
focusItem( $options.eq( $active.length ? ($active.index('.sel_dialog_item') + 1) : 0 ) );
|
|
198
|
+
event.preventDefault();
|
|
199
|
+
event.stopPropagation();
|
|
200
|
+
break;
|
|
201
|
+
|
|
202
|
+
case 'ArrowUp':
|
|
203
|
+
focusItem( $options.eq( $active.length ? Math.max(0, $active.index('.sel_dialog_item') - 1) : 0 ) );
|
|
204
|
+
event.preventDefault();
|
|
205
|
+
event.stopPropagation();
|
|
206
|
+
break;
|
|
207
|
+
|
|
208
|
+
case 'Enter':
|
|
209
|
+
case ' ':
|
|
210
|
+
if ($active.length) {
|
|
211
|
+
$active.click();
|
|
212
|
+
event.preventDefault();
|
|
213
|
+
event.stopPropagation();
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
|
|
217
|
+
case 'Escape':
|
|
218
|
+
Popover.detach();
|
|
219
|
+
event.preventDefault();
|
|
220
|
+
event.stopPropagation();
|
|
221
|
+
break;
|
|
222
|
+
} // switch key
|
|
223
|
+
}, // onKeyDown
|
|
224
|
+
|
|
170
225
|
popupQuickMenu: function(opts) {
|
|
171
226
|
// show popup menu on custom element
|
|
172
227
|
// opts: { elem, title, items, value, callback, nocheck?, onCancel? }
|
|
@@ -179,17 +234,20 @@ var SingleSelect = {
|
|
|
179
234
|
|
|
180
235
|
html += '<div class="sel_dialog_label">' + opts.title + '</div>';
|
|
181
236
|
if (opts.search) {
|
|
182
|
-
html += '<div class="sel_dialog_search_container">';
|
|
237
|
+
html += '<div class="sel_dialog_search_container" role="search">';
|
|
183
238
|
html += '<input type="text" id="fe_sel_dialog_search" class="sel_dialog_search" autocomplete="off" value=""/>';
|
|
184
239
|
html += '<div class="sel_dialog_search_icon"><i class="mdi mdi-magnify"></i></div>';
|
|
185
240
|
html += '</div>';
|
|
186
241
|
}
|
|
187
|
-
html += '<div id="d_sel_dialog_scrollarea" class="sel_dialog_scrollarea">';
|
|
242
|
+
html += '<div id="d_sel_dialog_scrollarea" class="sel_dialog_scrollarea" role="listbox">';
|
|
188
243
|
for (var idy = 0, ley = items.length; idy < ley; idy++) {
|
|
189
244
|
var item = items[idy];
|
|
190
245
|
var sel = (item.id == opts.value);
|
|
191
246
|
if (item.group) html += '<div class="sel_dialog_group">' + item.group + '</div>';
|
|
192
|
-
|
|
247
|
+
|
|
248
|
+
html += '<div class="sel_dialog_item ' + check + ' ' + (sel ? 'selected' : '') + ' shrinkwrap" data-value="' + item.id + '"';
|
|
249
|
+
html += ' role="option" aria-selected="' + (sel ? 'true' : 'false') + '" tabindex="-1">';
|
|
250
|
+
|
|
193
251
|
if (item.icon) html += '<i class="mdi mdi-' + item.icon + '"> </i>';
|
|
194
252
|
html += '<span>' + item.title + '</span>';
|
|
195
253
|
if (!opts.nocheck) html += '<div class="sel_dialog_item_check"><i class="mdi mdi-check"></i></div>';
|
|
@@ -199,7 +257,7 @@ var SingleSelect = {
|
|
|
199
257
|
|
|
200
258
|
Popover.attach( $elem, '<div style="padding:15px;">' + html + '</div>', true );
|
|
201
259
|
|
|
202
|
-
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').on('
|
|
260
|
+
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').on('click', function() {
|
|
203
261
|
// select item, close dialog and update state
|
|
204
262
|
var $item = $(this);
|
|
205
263
|
var value = $item.data('value');
|
|
@@ -207,10 +265,13 @@ var SingleSelect = {
|
|
|
207
265
|
delete opts.onCancel;
|
|
208
266
|
Popover.detach();
|
|
209
267
|
callback(value);
|
|
210
|
-
}); //
|
|
268
|
+
}); // click
|
|
269
|
+
|
|
270
|
+
// handle keyboard focus
|
|
271
|
+
Popover.onKeyDown = SingleSelect.handleKeyDown;
|
|
211
272
|
|
|
212
273
|
Popover.onDetach = function() {
|
|
213
|
-
$elem.removeClass('popped');
|
|
274
|
+
$elem.removeClass('popped').focus();
|
|
214
275
|
if (opts.onCancel) opts.onCancel();
|
|
215
276
|
};
|
|
216
277
|
|
|
@@ -249,7 +310,7 @@ var SingleSelect = {
|
|
|
249
310
|
event.preventDefault();
|
|
250
311
|
event.stopPropagation();
|
|
251
312
|
|
|
252
|
-
var mup = jQuery.Event( "
|
|
313
|
+
var mup = jQuery.Event( "click" );
|
|
253
314
|
mup.metaKey = true; // bypass `hold` feature
|
|
254
315
|
$('#d_sel_dialog_scrollarea > div.sel_dialog_item.match').slice(0, 1).trigger(mup);
|
|
255
316
|
}
|
|
@@ -266,9 +327,9 @@ var MultiSelect = {
|
|
|
266
327
|
$(sel).each( function() {
|
|
267
328
|
var self = this;
|
|
268
329
|
var $this = $(this);
|
|
269
|
-
$this.css('display', 'none');
|
|
330
|
+
$this.css('display', 'none').attr({ 'aria-hidden': true, 'tabindex': '-1' });
|
|
270
331
|
|
|
271
|
-
var $ms = $('<div class="multiselect multi"></div>');
|
|
332
|
+
var $ms = $('<div class="multiselect multi" role="button" tabindex="0" aria-haspopup="listbox" aria-expanded="false"></div>');
|
|
272
333
|
if ($this.data('compact')) $ms.addClass('compact');
|
|
273
334
|
if ($this.data('private')) $ms.attr('data-private', 1);
|
|
274
335
|
$this.after( $ms );
|
|
@@ -311,7 +372,7 @@ var MultiSelect = {
|
|
|
311
372
|
if (num_sel) $ms.append( '<div class="clear"></div>' );
|
|
312
373
|
else $ms.append( '<div class="placeholder">' + ($this.attr('placeholder') || 'Click to select...') + '</div>' );
|
|
313
374
|
|
|
314
|
-
$ms.find('div.item > i.mdi-close').on('
|
|
375
|
+
$ms.find('div.item > i.mdi-close').on('click', function(e) {
|
|
315
376
|
// user clicked on the 'X' -- remove this item and redraw
|
|
316
377
|
var $item = $(this).parent();
|
|
317
378
|
var value = $item.data('value');
|
|
@@ -335,8 +396,8 @@ var MultiSelect = {
|
|
|
335
396
|
|
|
336
397
|
if ($this.data('hold') && $this.data('volatile') && Popover.enabled && (Popover.$anchor.prop('id') == $this.prop('id'))) {
|
|
337
398
|
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').each( function(idx) {
|
|
338
|
-
if (self.options[idx].selected) $(this).addClass('selected');
|
|
339
|
-
else $(this).removeClass('selected');
|
|
399
|
+
if (self.options[idx].selected) $(this).addClass('selected').attr('aria-selected', 'true');
|
|
400
|
+
else $(this).removeClass('selected').attr('aria-selected', 'false');
|
|
340
401
|
} );
|
|
341
402
|
}
|
|
342
403
|
}; // redraw
|
|
@@ -349,7 +410,15 @@ var MultiSelect = {
|
|
|
349
410
|
// also expose redraw as a custom event that can be triggered
|
|
350
411
|
$this.on('redraw', redraw);
|
|
351
412
|
|
|
352
|
-
|
|
413
|
+
// allow keyboard to open menu
|
|
414
|
+
$ms.on('keydown', function(event) {
|
|
415
|
+
if ((event.key == 'Enter') || (event.key == ' ')) {
|
|
416
|
+
$ms.click();
|
|
417
|
+
event.preventDefault();
|
|
418
|
+
}
|
|
419
|
+
} );
|
|
420
|
+
|
|
421
|
+
$ms.on('click', function() {
|
|
353
422
|
// create popover dialog for selecting and filtering
|
|
354
423
|
var html = '';
|
|
355
424
|
var orig_sel_state = [];
|
|
@@ -357,6 +426,7 @@ var MultiSelect = {
|
|
|
357
426
|
var inherited = $this.data('inherited') ? ($this.data('inherited') || '').split(/\,\s*/) : [];
|
|
358
427
|
var is_private = $this.data('private');
|
|
359
428
|
if ($ms.hasClass('disabled')) return;
|
|
429
|
+
$ms.attr('aria-expanded', 'true');
|
|
360
430
|
|
|
361
431
|
html += '<div class="sel_dialog_label">' + ($this.attr('title') || 'Select Items');
|
|
362
432
|
if ($this.data('select-all')) {
|
|
@@ -365,11 +435,11 @@ var MultiSelect = {
|
|
|
365
435
|
}
|
|
366
436
|
html += '</div>';
|
|
367
437
|
|
|
368
|
-
html += '<div class="sel_dialog_search_container">';
|
|
438
|
+
html += '<div class="sel_dialog_search_container" role="search">';
|
|
369
439
|
html += '<input type="text" id="fe_sel_dialog_search" class="sel_dialog_search" autocomplete="off" value=""/>';
|
|
370
440
|
html += '<div class="sel_dialog_search_icon"><i class="mdi mdi-magnify"></i></div>';
|
|
371
441
|
html += '</div>';
|
|
372
|
-
html += '<div id="d_sel_dialog_scrollarea" class="sel_dialog_scrollarea">';
|
|
442
|
+
html += '<div id="d_sel_dialog_scrollarea" class="sel_dialog_scrollarea" role="listbox">';
|
|
373
443
|
|
|
374
444
|
for (var idx = 0, len = self.options.length; idx < len; idx++) {
|
|
375
445
|
var opt = self.options[idx];
|
|
@@ -387,7 +457,9 @@ var MultiSelect = {
|
|
|
387
457
|
if ($this.data('shrinkwrap')) html += ' shrinkwrap';
|
|
388
458
|
if (is_inherited) html += ' inherited';
|
|
389
459
|
|
|
390
|
-
html += '" data-value="' + opt.value + '" title="' + (is_inherited ? ($this.data('itooltip') || '(Inherited Item)') : '') + '"
|
|
460
|
+
html += '" data-value="' + opt.value + '" title="' + (is_inherited ? ($this.data('itooltip') || '(Inherited Item)') : '') + '"';
|
|
461
|
+
html += ' role="option" aria-selected="' + (opt.selected ? 'true' : 'false') + '" tabindex="-1">';
|
|
462
|
+
|
|
391
463
|
if (opt.getAttribute && opt.getAttribute('data-icon')) {
|
|
392
464
|
html += '<i class="mdi mdi-' + opt.getAttribute('data-icon') + '"> </i>';
|
|
393
465
|
}
|
|
@@ -409,7 +481,7 @@ var MultiSelect = {
|
|
|
409
481
|
|
|
410
482
|
Popover.attach( $ms, '<div style="padding:15px;">' + html + '</div>', $this.data('shrinkwrap') || false );
|
|
411
483
|
|
|
412
|
-
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').on('
|
|
484
|
+
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').on('click', function(event) {
|
|
413
485
|
// select item, close dialog and update multi-select
|
|
414
486
|
var $item = $(this);
|
|
415
487
|
if ($item.hasClass('inherited')) return; // no clicky on inherited items
|
|
@@ -422,7 +494,7 @@ var MultiSelect = {
|
|
|
422
494
|
var opt = self.options[idx];
|
|
423
495
|
if (opt.value == value) {
|
|
424
496
|
opt.selected = new_sel_state;
|
|
425
|
-
if (new_sel_state) $item.addClass('selected'); else $item.removeClass('selected');
|
|
497
|
+
if (new_sel_state) $item.addClass('selected').attr('aria-selected', 'true'); else $item.removeClass('selected').attr('aria-selected', 'false');
|
|
426
498
|
if (new_sel_state) new_sel_idx = idx;
|
|
427
499
|
idx = len;
|
|
428
500
|
}
|
|
@@ -436,7 +508,7 @@ var MultiSelect = {
|
|
|
436
508
|
// select range
|
|
437
509
|
if (last_sel_idx > new_sel_idx) { var temp = last_sel_idx; last_sel_idx = new_sel_idx; new_sel_idx = temp; }
|
|
438
510
|
for (var idx = last_sel_idx; idx <= new_sel_idx; idx++) { self.options[idx].selected = true; }
|
|
439
|
-
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').slice(last_sel_idx, new_sel_idx + 1).addClass('selected');
|
|
511
|
+
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').slice(last_sel_idx, new_sel_idx + 1).addClass('selected').attr('aria-selected', 'true');
|
|
440
512
|
}
|
|
441
513
|
else if ($this.data('hold') && event.altKey && (new_sel_idx > -1) && (last_sel_idx > -1) && (new_sel_idx != last_sel_idx)) {
|
|
442
514
|
// select pattern
|
|
@@ -445,7 +517,7 @@ var MultiSelect = {
|
|
|
445
517
|
for (var idx = last_sel_idx, len = self.options.length; idx < len; idx += dist) {
|
|
446
518
|
var opt = self.options[idx];
|
|
447
519
|
opt.selected = true;
|
|
448
|
-
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').slice(idx, idx + 1).addClass('selected');
|
|
520
|
+
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').slice(idx, idx + 1).addClass('selected').attr('aria-selected', 'true');
|
|
449
521
|
}
|
|
450
522
|
}
|
|
451
523
|
else if ($this.data('hold') && !new_sel_state) {
|
|
@@ -461,10 +533,10 @@ var MultiSelect = {
|
|
|
461
533
|
var is_all_sel = !!(find_objects(self.options, { selected: true }).length == self.options.length);
|
|
462
534
|
$('div.arrow_box div.sel_all_none').html( is_all_sel ? 'Select None' : 'Select All' );
|
|
463
535
|
}
|
|
464
|
-
}); //
|
|
536
|
+
}); // click
|
|
465
537
|
|
|
466
538
|
if ($this.data('hold')) {
|
|
467
|
-
$('#btn_sel_dialog_cancel').on('
|
|
539
|
+
$('#btn_sel_dialog_cancel').on('click', function() {
|
|
468
540
|
Popover.detach();
|
|
469
541
|
|
|
470
542
|
// restore original opts and redraw
|
|
@@ -476,11 +548,11 @@ var MultiSelect = {
|
|
|
476
548
|
redraw();
|
|
477
549
|
$this.trigger('change');
|
|
478
550
|
});
|
|
479
|
-
$('#btn_sel_dialog_add').on('
|
|
551
|
+
$('#btn_sel_dialog_add').on('click', function() { Popover.detach(); $ms.focus(); });
|
|
480
552
|
} // hold
|
|
481
553
|
|
|
482
554
|
// attach click handler for select-all-none
|
|
483
|
-
$('div.arrow_box div.sel_all_none').on('
|
|
555
|
+
$('div.arrow_box div.sel_all_none').on('click', function(event) {
|
|
484
556
|
var is_all_sel = !!(find_objects(self.options, { selected: true }).length == self.options.length);
|
|
485
557
|
var new_sel_state = !is_all_sel;
|
|
486
558
|
|
|
@@ -490,7 +562,7 @@ var MultiSelect = {
|
|
|
490
562
|
|
|
491
563
|
var opt = self.options[idx];
|
|
492
564
|
opt.selected = new_sel_state;
|
|
493
|
-
if (new_sel_state) $item.addClass('selected'); else $item.removeClass('selected');
|
|
565
|
+
if (new_sel_state) $item.addClass('selected').attr('aria-selected', 'true'); else $item.removeClass('selected').attr('aria-selected', 'false');
|
|
494
566
|
} );
|
|
495
567
|
|
|
496
568
|
$this.trigger('change');
|
|
@@ -535,7 +607,7 @@ var MultiSelect = {
|
|
|
535
607
|
event.preventDefault();
|
|
536
608
|
event.stopPropagation();
|
|
537
609
|
|
|
538
|
-
var mup = jQuery.Event( "
|
|
610
|
+
var mup = jQuery.Event( "click" );
|
|
539
611
|
mup.metaKey = true; // bypass `hold` feature
|
|
540
612
|
$('#d_sel_dialog_scrollarea > div.sel_dialog_item.match').slice(0, 1).trigger(mup);
|
|
541
613
|
}
|
|
@@ -543,13 +615,13 @@ var MultiSelect = {
|
|
|
543
615
|
// enter key WITHOUT value typed into search box + hold mode
|
|
544
616
|
event.preventDefault();
|
|
545
617
|
event.stopPropagation();
|
|
546
|
-
$('#btn_sel_dialog_add').trigger( jQuery.Event("
|
|
618
|
+
$('#btn_sel_dialog_add').trigger( jQuery.Event("click") );
|
|
547
619
|
}
|
|
548
620
|
else if ((event.keyCode == 27) && $this.data('hold')) {
|
|
549
621
|
// esc key WITHOUT value typed into search box + hold mode
|
|
550
622
|
event.preventDefault();
|
|
551
623
|
event.stopPropagation();
|
|
552
|
-
$('#btn_sel_dialog_cancel').trigger( jQuery.Event("
|
|
624
|
+
$('#btn_sel_dialog_cancel').trigger( jQuery.Event("click") );
|
|
553
625
|
}
|
|
554
626
|
});
|
|
555
627
|
|
|
@@ -559,23 +631,26 @@ var MultiSelect = {
|
|
|
559
631
|
// enter key
|
|
560
632
|
event.preventDefault();
|
|
561
633
|
event.stopPropagation();
|
|
562
|
-
$('#btn_sel_dialog_add').trigger( jQuery.Event("
|
|
634
|
+
$('#btn_sel_dialog_add').trigger( jQuery.Event("click") );
|
|
563
635
|
}
|
|
564
636
|
else if ((event.keyCode == 27) && !$input.is(':focus') && $this.data('hold')) {
|
|
565
637
|
// esc key
|
|
566
638
|
event.preventDefault();
|
|
567
639
|
event.stopPropagation();
|
|
568
|
-
$('#btn_sel_dialog_cancel').trigger( jQuery.Event("
|
|
640
|
+
$('#btn_sel_dialog_cancel').trigger( jQuery.Event("click") );
|
|
569
641
|
}
|
|
570
642
|
};
|
|
571
643
|
|
|
644
|
+
// handle keyboard focus
|
|
645
|
+
Popover.onKeyDown = SingleSelect.handleKeyDown;
|
|
646
|
+
|
|
572
647
|
// highlight multiselect field under us
|
|
573
648
|
$ms.addClass('selected');
|
|
574
649
|
Popover.onDetach = function() {
|
|
575
|
-
$ms.removeClass('selected');
|
|
650
|
+
$ms.removeClass('selected').attr('aria-expanded', 'false').focus();
|
|
576
651
|
if (Dialog.active) Dialog.autoResize();
|
|
577
652
|
};
|
|
578
|
-
}); //
|
|
653
|
+
}); // click
|
|
579
654
|
|
|
580
655
|
}); // foreach elem
|
|
581
656
|
},
|
|
@@ -591,16 +666,19 @@ var MultiSelect = {
|
|
|
591
666
|
|
|
592
667
|
html += '<div class="sel_dialog_label">' + opts.title + '</div>';
|
|
593
668
|
if (opts.search) {
|
|
594
|
-
html += '<div class="sel_dialog_search_container">';
|
|
669
|
+
html += '<div class="sel_dialog_search_container" role="search">';
|
|
595
670
|
html += '<input type="text" id="fe_sel_dialog_search" class="sel_dialog_search" autocomplete="off" value=""/>';
|
|
596
671
|
html += '<div class="sel_dialog_search_icon"><i class="mdi mdi-magnify"></i></div>';
|
|
597
672
|
html += '</div>';
|
|
598
673
|
}
|
|
599
|
-
html += '<div id="d_sel_dialog_scrollarea" class="sel_dialog_scrollarea">';
|
|
674
|
+
html += '<div id="d_sel_dialog_scrollarea" class="sel_dialog_scrollarea" role="listbox">';
|
|
600
675
|
for (var idy = 0, ley = items.length; idy < ley; idy++) {
|
|
601
676
|
var item = items[idy];
|
|
602
677
|
var sel = opts.values.includes(item.id);
|
|
603
|
-
|
|
678
|
+
|
|
679
|
+
html += '<div class="sel_dialog_item check ' + (sel ? 'selected' : '') + ' shrinkwrap" data-value="' + item.id + '"';
|
|
680
|
+
html += ' role="option" aria-selected="' + (sel ? 'true' : 'false') + '" tabindex="-1">';
|
|
681
|
+
|
|
604
682
|
if (item.icon) html += '<i class="mdi mdi-' + item.icon + '"> </i>';
|
|
605
683
|
html += '<span>' + item.title + '</span>';
|
|
606
684
|
html += '<div class="sel_dialog_item_check"><i class="mdi mdi-check"></i></div>';
|
|
@@ -610,7 +688,7 @@ var MultiSelect = {
|
|
|
610
688
|
|
|
611
689
|
Popover.attach( $elem, '<div style="padding:15px;">' + html + '</div>', true );
|
|
612
690
|
|
|
613
|
-
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').on('
|
|
691
|
+
$('#d_sel_dialog_scrollarea > div.sel_dialog_item').on('click', function() {
|
|
614
692
|
// select item, close dialog and update state
|
|
615
693
|
var $item = $(this);
|
|
616
694
|
if ($item.hasClass('selected')) $item.removeClass('selected');
|
|
@@ -623,10 +701,13 @@ var MultiSelect = {
|
|
|
623
701
|
|
|
624
702
|
Popover.detach();
|
|
625
703
|
callback(values);
|
|
626
|
-
}); //
|
|
704
|
+
}); // click
|
|
705
|
+
|
|
706
|
+
// handle keyboard focus
|
|
707
|
+
Popover.onKeyDown = SingleSelect.handleKeyDown;
|
|
627
708
|
|
|
628
709
|
Popover.onDetach = function() {
|
|
629
|
-
$elem.removeClass('popped');
|
|
710
|
+
$elem.removeClass('popped').focus();
|
|
630
711
|
};
|
|
631
712
|
|
|
632
713
|
$elem.addClass('popped');
|
|
@@ -664,7 +745,7 @@ var MultiSelect = {
|
|
|
664
745
|
event.preventDefault();
|
|
665
746
|
event.stopPropagation();
|
|
666
747
|
|
|
667
|
-
var mup = jQuery.Event( "
|
|
748
|
+
var mup = jQuery.Event( "click" );
|
|
668
749
|
mup.metaKey = true; // bypass `hold` feature
|
|
669
750
|
$('#d_sel_dialog_scrollarea > div.sel_dialog_item.match').slice(0, 1).trigger(mup);
|
|
670
751
|
}
|
|
@@ -681,8 +762,9 @@ var TextSelect = {
|
|
|
681
762
|
$(sel).each( function() {
|
|
682
763
|
var self = this;
|
|
683
764
|
var $this = $(this);
|
|
765
|
+
$this.css('display', 'none').attr({ 'aria-hidden': true, 'tabindex': '-1' });
|
|
684
766
|
|
|
685
|
-
var $ms = $('<div class="multiselect text"></div>');
|
|
767
|
+
var $ms = $('<div class="multiselect text" role="button" tabindex="0"></div>');
|
|
686
768
|
$this.after( $ms );
|
|
687
769
|
|
|
688
770
|
var redraw = function() {
|
|
@@ -703,7 +785,7 @@ var TextSelect = {
|
|
|
703
785
|
if (num_sel) $ms.append( '<div class="clear"></div>' );
|
|
704
786
|
else $ms.append( '<div class="placeholder">' + ($this.attr('placeholder') || 'Click to add...') + '</div>' );
|
|
705
787
|
|
|
706
|
-
$ms.find('div.item > i').on('
|
|
788
|
+
$ms.find('div.item > i').on('click', function(e) {
|
|
707
789
|
// user clicked on the 'X' -- remove this item and redraw
|
|
708
790
|
var $item = $(this).parent();
|
|
709
791
|
var value = $item.data('value');
|
|
@@ -726,7 +808,15 @@ var TextSelect = {
|
|
|
726
808
|
// also expose redraw as a custom event that can be triggered
|
|
727
809
|
$this.on('redraw', redraw);
|
|
728
810
|
|
|
729
|
-
|
|
811
|
+
// allow keyboard to open menu
|
|
812
|
+
$ms.on('keydown', function(event) {
|
|
813
|
+
if ((event.key == 'Enter') || (event.key == ' ')) {
|
|
814
|
+
$ms.click();
|
|
815
|
+
event.preventDefault();
|
|
816
|
+
}
|
|
817
|
+
} );
|
|
818
|
+
|
|
819
|
+
$ms.on('click', function() {
|
|
730
820
|
// create popover dialog for adding new items
|
|
731
821
|
var html = '';
|
|
732
822
|
if ($ms.hasClass('disabled')) return;
|
|
@@ -772,8 +862,8 @@ var TextSelect = {
|
|
|
772
862
|
$this.trigger('change');
|
|
773
863
|
}; // doAdd
|
|
774
864
|
|
|
775
|
-
$('#btn_sel_dialog_cancel').on('
|
|
776
|
-
$('#btn_sel_dialog_add').on('
|
|
865
|
+
$('#btn_sel_dialog_cancel').on('click', function() { Popover.detach(); });
|
|
866
|
+
$('#btn_sel_dialog_add').on('click', function() { doAdd(); });
|
|
777
867
|
|
|
778
868
|
var $input = $('#fe_sel_dialog_text').focus().on('keydown', function(event) {
|
|
779
869
|
// capture enter key
|
|
@@ -786,8 +876,10 @@ var TextSelect = {
|
|
|
786
876
|
|
|
787
877
|
// highlight multiselect field under us
|
|
788
878
|
$ms.addClass('selected');
|
|
789
|
-
Popover.onDetach = function() {
|
|
790
|
-
|
|
879
|
+
Popover.onDetach = function() {
|
|
880
|
+
$ms.removeClass('selected').focus();
|
|
881
|
+
};
|
|
882
|
+
}); // click
|
|
791
883
|
|
|
792
884
|
}); // forach elem
|
|
793
885
|
},
|
|
@@ -835,8 +927,8 @@ var TextSelect = {
|
|
|
835
927
|
callback(value);
|
|
836
928
|
}; // doAdd
|
|
837
929
|
|
|
838
|
-
$('#btn_sel_dialog_cancel').on('
|
|
839
|
-
$('#btn_sel_dialog_add').on('
|
|
930
|
+
$('#btn_sel_dialog_cancel').on('click', function() { Popover.detach(); });
|
|
931
|
+
$('#btn_sel_dialog_add').on('click', function() { doAdd(); });
|
|
840
932
|
|
|
841
933
|
var $input = $('#fe_sel_dialog_text').focus().on('keydown', function(event) {
|
|
842
934
|
// capture enter key
|
|
@@ -848,7 +940,9 @@ var TextSelect = {
|
|
|
848
940
|
});
|
|
849
941
|
|
|
850
942
|
$elem.addClass('popped');
|
|
851
|
-
Popover.onDetach = function() {
|
|
943
|
+
Popover.onDetach = function() {
|
|
944
|
+
$elem.removeClass('popped').focus();
|
|
945
|
+
};
|
|
852
946
|
}
|
|
853
947
|
|
|
854
948
|
}; // TextSelect
|
package/js/tools.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
////
|
|
2
2
|
// Joe's Misc JavaScript Tools
|
|
3
|
-
// Copyright (c) 2004 -
|
|
4
|
-
// Released under the
|
|
3
|
+
// Copyright (c) 2004 - 2026 Joseph Huckaby
|
|
4
|
+
// Released under the BSD 3-Clause License
|
|
5
5
|
////
|
|
6
6
|
|
|
7
7
|
var months = [
|
|
@@ -560,7 +560,7 @@ function expando_text(text, max, link) {
|
|
|
560
560
|
var after = text.substring(max);
|
|
561
561
|
|
|
562
562
|
return before +
|
|
563
|
-
'<span>... <a href="javascript:void(0)"
|
|
563
|
+
'<span>... <a href="javascript:void(0)" onClick="$(this).parent().hide().next().show()">'+link+'</a></span>' +
|
|
564
564
|
'<span style="display:none">' + after + '</span>';
|
|
565
565
|
};
|
|
566
566
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pixl-xyapp",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.9",
|
|
4
4
|
"description": "A theme for xyOps.",
|
|
5
5
|
"author": "Joseph Huckaby <jhuckaby@pixlcore.com>",
|
|
6
6
|
"homepage": "https://github.com/pixlcore/pixl-xyapp",
|
|
7
|
-
"license": "
|
|
7
|
+
"license": "BSD-3-Clause",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/pixlcore/pixl-xyapp"
|
|
10
|
+
"url": "git+https://github.com/pixlcore/pixl-xyapp.git"
|
|
11
11
|
},
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/pixlcore/pixl-xyapp/issues"
|