pixl-xyapp 2.1.0
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 +11 -0
- package/README.md +485 -0
- package/css/base.css +2736 -0
- package/css/boilerplate.css +295 -0
- package/css/normalize.css +349 -0
- package/js/base.js +648 -0
- package/js/calendar.js +166 -0
- package/js/datetime.js +233 -0
- package/js/dialog.js +385 -0
- package/js/misc.js +311 -0
- package/js/page.js +1940 -0
- package/js/popover.js +158 -0
- package/js/select.js +845 -0
- package/js/tools.js +1212 -0
- package/js/unscroll.min.js +3 -0
- package/package.json +20 -0
package/js/calendar.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// Popup calendar component
|
|
2
|
+
|
|
3
|
+
var Calendar = {
|
|
4
|
+
|
|
5
|
+
init: function(sel) {
|
|
6
|
+
// initialize all based on selector
|
|
7
|
+
$(sel).each( function() {
|
|
8
|
+
var $this = $(this);
|
|
9
|
+
var $anchor = $this.next();
|
|
10
|
+
|
|
11
|
+
$anchor.on('mouseup', function() {
|
|
12
|
+
Calendar.popup( $anchor, parseInt($this.val()), function(epoch) {
|
|
13
|
+
$this.val( epoch );
|
|
14
|
+
$this.trigger('change');
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
$this.on('change', function() {
|
|
19
|
+
var epoch = parseInt(this.value);
|
|
20
|
+
if (epoch) {
|
|
21
|
+
var fmt = app.formatDate(epoch, {
|
|
22
|
+
year: 'numeric',
|
|
23
|
+
month: 'long',
|
|
24
|
+
day: 'numeric'
|
|
25
|
+
});
|
|
26
|
+
$anchor.html( '<i class="mdi mdi-calendar"> </i>' + fmt );
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
$anchor.html( '(None)' );
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
$this.trigger('change');
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
popup: function(anchor, date, callback) {
|
|
38
|
+
var self = this;
|
|
39
|
+
var html = '';
|
|
40
|
+
if (!date) date = time_now();
|
|
41
|
+
|
|
42
|
+
this.$anchor = $(anchor);
|
|
43
|
+
this.callback = callback;
|
|
44
|
+
this.sel_epoch = normalize_time( date, { hour: 0, min: 0, sec: 0 } );
|
|
45
|
+
this.month_start_epoch = normalize_time( this.sel_epoch, { mday: 1, hour: 12, min: 0, sec: 0 } );
|
|
46
|
+
|
|
47
|
+
html += '<div class="calendar">';
|
|
48
|
+
html += '<div class="cal_header">';
|
|
49
|
+
html += '<div class="ch_nav ch_prev" onMouseUp="Calendar.prevMonth()" title="Previous Month"><i class="mdi mdi-chevron-double-left"></i></div>';
|
|
50
|
+
html += '<div class="ch_title"></div>';
|
|
51
|
+
html += '<div class="ch_nav ch_next" onMouseUp="Calendar.nextMonth()" title="Next Month"><i class="mdi mdi-chevron-double-right"></i></div>';
|
|
52
|
+
html += '</div>';
|
|
53
|
+
html += '<div class="cal_days">';
|
|
54
|
+
_short_day_names.forEach( function(ddd) {
|
|
55
|
+
html += '<div class="cal_day">' + ddd + '</div>';
|
|
56
|
+
});
|
|
57
|
+
html += '</div>';
|
|
58
|
+
html += '<div class="cal_grid">';
|
|
59
|
+
for (var y = 0; y < 6; y++) {
|
|
60
|
+
html += '<div class="cg_row">';
|
|
61
|
+
for (var x = 0; x < 7; x++) {
|
|
62
|
+
html += '<div class="cg_cell" id="cg_' + x + '_' + y + '"></div>';
|
|
63
|
+
}
|
|
64
|
+
html += '</div>';
|
|
65
|
+
}
|
|
66
|
+
html += '</div>';
|
|
67
|
+
html += '</div>';
|
|
68
|
+
|
|
69
|
+
Popover.attach( this.$anchor, html, true );
|
|
70
|
+
|
|
71
|
+
// save this for convenience
|
|
72
|
+
this.$cal = Popover.$box.find('div.calendar');
|
|
73
|
+
|
|
74
|
+
// add click handling to grid
|
|
75
|
+
this.$cal.find('div.cg_cell').on('mouseup', function() {
|
|
76
|
+
var mday = $(this).data('mday') || '';
|
|
77
|
+
if (mday) self.clickCell( mday );
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// draw initial calendar
|
|
81
|
+
this.redraw();
|
|
82
|
+
|
|
83
|
+
// highlight anchor field under us
|
|
84
|
+
this.$anchor.addClass('selected');
|
|
85
|
+
|
|
86
|
+
// arrow key navigation within popup
|
|
87
|
+
Popover.onKeyDown = function(event) {
|
|
88
|
+
if (event.keyCode == 37) self.prevMonth();
|
|
89
|
+
else if (event.keyCode == 39) self.nextMonth();
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// cleanup on close
|
|
93
|
+
Popover.onDetach = function() {
|
|
94
|
+
self.$anchor.removeClass('selected');
|
|
95
|
+
delete self.$anchor;
|
|
96
|
+
delete self.callback;
|
|
97
|
+
delete self.sel_epoch;
|
|
98
|
+
delete self.month_start_epoch;
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
redraw: function() {
|
|
103
|
+
// draw current month
|
|
104
|
+
var self = this;
|
|
105
|
+
var $cal = this.$cal;
|
|
106
|
+
var month_start_epoch = this.month_start_epoch;
|
|
107
|
+
var sel_dargs = get_date_args( this.sel_epoch );
|
|
108
|
+
var today_dargs = get_date_args();
|
|
109
|
+
|
|
110
|
+
// title
|
|
111
|
+
var month_dargs = get_date_args( this.month_start_epoch );
|
|
112
|
+
$cal.find('div.ch_title').html( month_dargs.mmmm + ' ' + month_dargs.yyyy );
|
|
113
|
+
|
|
114
|
+
// setup grid
|
|
115
|
+
$cal.find('div.cg_cell').empty().removeClass().addClass('cg_cell').removeData('mday');
|
|
116
|
+
$cal.find('div.cg_row').removeClass('last');
|
|
117
|
+
|
|
118
|
+
// populate real day grid units
|
|
119
|
+
var epoch = month_start_epoch;
|
|
120
|
+
var dargs = get_date_args( epoch );
|
|
121
|
+
var y = -1;
|
|
122
|
+
|
|
123
|
+
while (dargs.yyyy_mm == month_dargs.yyyy_mm) {
|
|
124
|
+
var x = dargs.wday;
|
|
125
|
+
if ((y == -1) || (x == 0)) y++;
|
|
126
|
+
var $cell = $cal.find('#cg_' + x + '_' + y);
|
|
127
|
+
$cell.addClass('enabled').html(dargs.mday).data('mday', dargs.mday);
|
|
128
|
+
|
|
129
|
+
// augment class for current date and selected date
|
|
130
|
+
if (dargs.yyyy_mm_dd == sel_dargs.yyyy_mm_dd) $cell.addClass('selected');
|
|
131
|
+
if (dargs.yyyy_mm_dd == today_dargs.yyyy_mm_dd) $cell.addClass('today');
|
|
132
|
+
|
|
133
|
+
// since we started at noon, this avoids DST issues
|
|
134
|
+
epoch += 86400;
|
|
135
|
+
dargs = get_date_args( epoch );
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// fix up borders and reposition popover in case height has changed
|
|
139
|
+
$cal.find('div.cg_row').slice(y).addClass('last');
|
|
140
|
+
Popover.reposition();
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
clickCell: function(mday) {
|
|
144
|
+
// user clicked on enabled grid cell -- fire callback and detach popover
|
|
145
|
+
var epoch = normalize_time( this.month_start_epoch, { mday: parseInt(mday), hour: 0, min: 0, sec: 0 } );
|
|
146
|
+
this.callback( epoch );
|
|
147
|
+
Popover.detach();
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
prevMonth: function() {
|
|
151
|
+
// jump to previous month
|
|
152
|
+
var dargs = get_date_args( this.month_start_epoch );
|
|
153
|
+
dargs.mon--; if (dargs.mon < 1) { dargs.mon = 12; dargs.year--; }
|
|
154
|
+
this.month_start_epoch = get_time_from_args( dargs );
|
|
155
|
+
this.redraw();
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
nextMonth: function() {
|
|
159
|
+
// jump to next month
|
|
160
|
+
var dargs = get_date_args( this.month_start_epoch );
|
|
161
|
+
dargs.mon++; if (dargs.mon > 12) { dargs.mon = 1; dargs.year++; }
|
|
162
|
+
this.month_start_epoch = get_time_from_args( dargs );
|
|
163
|
+
this.redraw();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
}; // Calendar
|
package/js/datetime.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// Joe's Date/Time Tools
|
|
2
|
+
// Copyright (c) 2004 - 2025 Joseph Huckaby
|
|
3
|
+
// Released under the Sustainable Use License
|
|
4
|
+
|
|
5
|
+
var _months = [
|
|
6
|
+
[ 1, 'January' ], [ 2, 'February' ], [ 3, 'March' ], [ 4, 'April' ],
|
|
7
|
+
[ 5, 'May' ], [ 6, 'June' ], [ 7, 'July' ], [ 8, 'August' ],
|
|
8
|
+
[ 9, 'September' ], [ 10, 'October' ], [ 11, 'November' ],
|
|
9
|
+
[ 12, 'December' ]
|
|
10
|
+
];
|
|
11
|
+
var _days = [
|
|
12
|
+
[1,1], [2,2], [3,3], [4,4], [5,5], [6,6], [7,7], [8,8], [9,9], [10,10],
|
|
13
|
+
[11,11], [12,12], [13,13], [14,14], [15,15], [16,16], [17,17], [18,18],
|
|
14
|
+
[19,19], [20,20], [21,21], [22,22], [23,23], [24,24], [25,25], [26,26],
|
|
15
|
+
[27,27], [28,28], [29,29], [30,30], [31,31]
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
var _short_month_names = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May',
|
|
19
|
+
'June', 'July', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec' ];
|
|
20
|
+
|
|
21
|
+
var _day_names = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
|
|
22
|
+
'Thursday', 'Friday', 'Saturday'];
|
|
23
|
+
|
|
24
|
+
var _short_day_names = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
25
|
+
|
|
26
|
+
var _number_suffixes = ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'];
|
|
27
|
+
|
|
28
|
+
var _hour_names = ['12am', '1am', '2am', '3am', '4am', '5am', '6am', '7am', '8am', '9am', '10am', '11am', '12pm', '1pm', '2pm', '3pm', '4pm', '5pm', '6pm', '7pm', '8pm', '9pm', '10pm', '11pm'];
|
|
29
|
+
|
|
30
|
+
function time_now() {
|
|
31
|
+
// return the Epoch seconds for like right now
|
|
32
|
+
var now = new Date();
|
|
33
|
+
return Math.floor( now.getTime() / 1000 );
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function hires_time_now() {
|
|
37
|
+
// return the Epoch seconds for like right now
|
|
38
|
+
var now = new Date();
|
|
39
|
+
return ( now.getTime() / 1000 );
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function format_date(thingy, template) {
|
|
43
|
+
// format date using get_date_args
|
|
44
|
+
// e.g. '[yyyy]/[mm]/[dd]' or '[dddd], [mmmm] [mday], [yyyy]' or '[hour12]:[mi] [ampm]'
|
|
45
|
+
if (!thingy) return false;
|
|
46
|
+
var dargs = thingy.yyyy_mm_dd ? thingy : get_date_args(thingy);
|
|
47
|
+
return template.replace(/\[(\w+)\]/g, function(m_all, m_g1) {
|
|
48
|
+
return (m_g1 in dargs) ? dargs[m_g1] : '';
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function get_date_args(thingy) {
|
|
53
|
+
// return hash containing year, mon, mday, hour, min, sec
|
|
54
|
+
// given epoch seconds
|
|
55
|
+
if (!thingy) thingy = new Date();
|
|
56
|
+
if ((typeof(thingy) == 'string') && thingy.match(/^(\d{4}\D+\d{2}\D+\d{2}|\d{2}\D+\d{2}\D+\d{4})$/)) {
|
|
57
|
+
// JS date parser seems to miss-calculate unless dates have times
|
|
58
|
+
thingy += ' 00:00:00';
|
|
59
|
+
}
|
|
60
|
+
var date = (typeof(thingy) == 'object') ? thingy : (new Date( (typeof(thingy) == 'number') ? (thingy * 1000) : thingy ));
|
|
61
|
+
var args = {
|
|
62
|
+
epoch: Math.floor( date.getTime() / 1000 ),
|
|
63
|
+
year: date.getFullYear(),
|
|
64
|
+
mon: date.getMonth() + 1,
|
|
65
|
+
mday: date.getDate(),
|
|
66
|
+
hour: date.getHours(),
|
|
67
|
+
min: date.getMinutes(),
|
|
68
|
+
sec: date.getSeconds(),
|
|
69
|
+
msec: date.getMilliseconds(),
|
|
70
|
+
wday: date.getDay(),
|
|
71
|
+
offset: 0 - (date.getTimezoneOffset() / 60)
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
args.yyyy = '' + args.year;
|
|
75
|
+
args.d = '' + args.mday;
|
|
76
|
+
if (args.mon < 10) args.mm = "0" + args.mon; else args.mm = '' + args.mon;
|
|
77
|
+
if (args.mday < 10) args.dd = "0" + args.mday; else args.dd = '' + args.mday;
|
|
78
|
+
if (args.hour < 10) args.hh = "0" + args.hour; else args.hh = '' + args.hour;
|
|
79
|
+
if (args.min < 10) args.mi = "0" + args.min; else args.mi = '' + args.min;
|
|
80
|
+
if (args.sec < 10) args.ss = "0" + args.sec; else args.ss = '' + args.sec;
|
|
81
|
+
|
|
82
|
+
if (args.hour >= 12) {
|
|
83
|
+
args.ampm = 'pm';
|
|
84
|
+
args.hour12 = args.hour - 12;
|
|
85
|
+
if (!args.hour12) args.hour12 = 12;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
args.ampm = 'am';
|
|
89
|
+
args.hour12 = args.hour;
|
|
90
|
+
if (!args.hour12) args.hour12 = 12;
|
|
91
|
+
}
|
|
92
|
+
args.h12 = '' + args.hour12;
|
|
93
|
+
|
|
94
|
+
args.ampm = args.ampm.toUpperCase();
|
|
95
|
+
args.yyyy_mm = args.yyyy + '/' + args.mm;
|
|
96
|
+
args.yyyy_mm_dd = args.yyyy + '/' + args.mm + '/' + args.dd;
|
|
97
|
+
args.hh_mi_ss = args.hh + ':' + args.mi + ':' + args.ss;
|
|
98
|
+
args.tz = 'GMT' + (args.offset > 0 ? '+' : '') + args.offset;
|
|
99
|
+
|
|
100
|
+
// add formatted month and weekdays
|
|
101
|
+
args.mmm = _short_month_names[ args.mon - 1 ];
|
|
102
|
+
args.mmmm = _months[ args.mon - 1] ? _months[ args.mon - 1][1] : '';
|
|
103
|
+
args.ddd = _short_day_names[ args.wday ];
|
|
104
|
+
args.dddd = _day_names[ args.wday ];
|
|
105
|
+
|
|
106
|
+
return args;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function get_time_from_args(args) {
|
|
110
|
+
// return epoch given args like those returned from get_date_args()
|
|
111
|
+
var then = new Date(
|
|
112
|
+
args.year,
|
|
113
|
+
args.mon - 1,
|
|
114
|
+
args.mday,
|
|
115
|
+
args.hour,
|
|
116
|
+
args.min,
|
|
117
|
+
args.sec,
|
|
118
|
+
0
|
|
119
|
+
);
|
|
120
|
+
return parseInt( then.getTime() / 1000, 10 );
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function yyyy(epoch) {
|
|
124
|
+
// return current year (or epoch) in YYYY format
|
|
125
|
+
if (!epoch) epoch = time_now();
|
|
126
|
+
var args = get_date_args(epoch);
|
|
127
|
+
return args.year;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function yyyy_mm_dd(epoch, ch) {
|
|
131
|
+
// return current date (or custom epoch) in YYYY/MM/DD format
|
|
132
|
+
if (!epoch) epoch = time_now();
|
|
133
|
+
if (!ch) ch = '/';
|
|
134
|
+
var args = get_date_args(epoch);
|
|
135
|
+
return args.yyyy + ch + args.mm + ch + args.dd;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function mm_dd_yyyy(epoch, ch) {
|
|
139
|
+
// return current date (or custom epoch) in YYYY/MM/DD format
|
|
140
|
+
if (!epoch) epoch = time_now();
|
|
141
|
+
if (!ch) ch = '/';
|
|
142
|
+
var args = get_date_args(epoch);
|
|
143
|
+
return args.mm + ch + args.dd + ch + args.yyyy;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function normalize_time(epoch, zero_args) {
|
|
147
|
+
// quantize time into any given precision
|
|
148
|
+
// example hourly: { min:0, sec:0 }
|
|
149
|
+
// daily: { hour:0, min:0, sec:0 }
|
|
150
|
+
var args = get_date_args(epoch);
|
|
151
|
+
for (key in zero_args) args[key] = zero_args[key];
|
|
152
|
+
|
|
153
|
+
// mday is 1-based
|
|
154
|
+
if (!args['mday']) args['mday'] = 1;
|
|
155
|
+
|
|
156
|
+
return get_time_from_args(args);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function get_nice_date(epoch, abbrev) {
|
|
160
|
+
var dargs = get_date_args(epoch);
|
|
161
|
+
var month = window._months[dargs.mon - 1][1];
|
|
162
|
+
if (abbrev) month = month.substring(0, 3);
|
|
163
|
+
return month + ' ' + dargs.mday + ', ' + dargs.year;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function get_nice_time(epoch, secs) {
|
|
167
|
+
// return time in HH12:MM format
|
|
168
|
+
var dargs = get_date_args(epoch);
|
|
169
|
+
if (dargs.min < 10) dargs.min = '0' + dargs.min;
|
|
170
|
+
if (dargs.sec < 10) dargs.sec = '0' + dargs.sec;
|
|
171
|
+
var output = dargs.hour12 + ':' + dargs.min;
|
|
172
|
+
if (secs) output += ':' + dargs.sec;
|
|
173
|
+
output += ' ' + dargs.ampm.toUpperCase();
|
|
174
|
+
return output;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function get_nice_date_time(epoch, secs, abbrev_date) {
|
|
178
|
+
return get_nice_date(epoch, abbrev_date) + ' ' + get_nice_time(epoch, secs);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function get_short_date_time(epoch) {
|
|
182
|
+
return get_nice_date(epoch, true) + ' ' + get_nice_time(epoch, false);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function parse_date(str) {
|
|
186
|
+
// parse date into epoch
|
|
187
|
+
return Math.floor( ((new Date(str)).getTime() / 1000) );
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
function check_valid_date(str) {
|
|
191
|
+
// return true if a date is valid, false otherwise
|
|
192
|
+
// returns false for Jan 1, 1970 00:00:00 GMT
|
|
193
|
+
var epoch = 0;
|
|
194
|
+
try { epoch = parse_date(str); }
|
|
195
|
+
catch (e) { epoch = 0; }
|
|
196
|
+
return (epoch >= 86400);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Relative Time Component
|
|
200
|
+
// create via getFormRelativeTime()
|
|
201
|
+
|
|
202
|
+
var RelativeTime = {
|
|
203
|
+
|
|
204
|
+
mults: {
|
|
205
|
+
seconds: 1,
|
|
206
|
+
minutes: 60,
|
|
207
|
+
hours: 3600,
|
|
208
|
+
days: 86400
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
init: function(sel) {
|
|
212
|
+
// initialize all based on selector
|
|
213
|
+
var self = this;
|
|
214
|
+
|
|
215
|
+
$(sel).each( function() {
|
|
216
|
+
var $this = $(this);
|
|
217
|
+
var $text = $this.next().find("input");
|
|
218
|
+
var $menu = $this.next().find("select");
|
|
219
|
+
var $both = $this.next().find("input, select");
|
|
220
|
+
|
|
221
|
+
$both.on('change', function() {
|
|
222
|
+
var adj_value = parseInt( $text.val() );
|
|
223
|
+
if (isNaN(adj_value) || (adj_value < 0)) return;
|
|
224
|
+
var unit = $menu.val();
|
|
225
|
+
var mult = self.mults[ unit ];
|
|
226
|
+
var value = adj_value * mult;
|
|
227
|
+
$this.val( value );
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
}; // RelativeTime
|
|
233
|
+
|