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/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">&nbsp;</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
+