iguazio.dashboard-controls 1.0.13 → 1.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/dist/i18n/en/common.json +15 -2
- package/dist/i18n/en/functions.json +1 -0
- package/dist/js/iguazio.dashboard-controls.js +13637 -12207
- package/dist/less/iguazio.dashboard-controls.less +3614 -3065
- package/package.json +1 -1
- package/src/i18n/en/common.json +15 -2
- package/src/i18n/en/functions.json +1 -0
- package/src/igz_controls/components/date-time-picker/date-time-picker.component.js +689 -0
- package/src/igz_controls/components/date-time-picker/date-time-picker.component.spec.js +356 -0
- package/src/igz_controls/components/date-time-picker/date-time-picker.less +418 -0
- package/src/igz_controls/components/date-time-picker/date-time-picker.tpl.html +90 -0
- package/src/igz_controls/components/date-time-picker/prevent-parent-scroll.directive.js +27 -0
- package/src/igz_controls/components/log-table-row/log-table-row.component.js +57 -0
- package/src/igz_controls/components/log-table-row/log-table-row.component.spec.js +49 -0
- package/src/igz_controls/components/log-table-row/log-table-row.less +29 -0
- package/src/igz_controls/components/log-table-row/log-table-row.tpl.html +16 -0
- package/src/igz_controls/components/multiple-checkboxes/multiple-checkboxes.component.js +39 -5
- package/src/igz_controls/services/control-panel-logs-data.service.js +203 -0
- package/src/nuclio/common/components/deploy-log/deploy-log.component.js +1 -1
- package/src/nuclio/common/services/export.service.js +28 -5
- package/src/nuclio/functions/version/version-execution-log/version-execution-log.component.js +463 -0
- package/src/nuclio/functions/version/version-execution-log/version-execution-log.less +99 -0
- package/src/nuclio/functions/version/version-execution-log/version-execution-log.tpl.html +177 -0
- package/src/nuclio/functions/version/version.component.js +29 -2
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2018 Iguazio Systems Ltd.
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License") with
|
|
4
|
+
an addition restriction as set forth herein. You may not use this
|
|
5
|
+
file except in compliance with the License. You may obtain a copy of
|
|
6
|
+
the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software
|
|
8
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
9
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
10
|
+
implied. See the License for the specific language governing
|
|
11
|
+
permissions and limitations under the License.
|
|
12
|
+
In addition, you may not use the software for any purposes that are
|
|
13
|
+
illegal under applicable law, and the grant of the foregoing license
|
|
14
|
+
under the Apache 2.0 license is conditioned upon your compliance with
|
|
15
|
+
such restriction.
|
|
16
|
+
*/
|
|
17
|
+
(function () {
|
|
18
|
+
'use strict';
|
|
19
|
+
/*eslint complexity: ["error", 13]*/
|
|
20
|
+
|
|
21
|
+
angular.module('iguazio.dashboard-controls')
|
|
22
|
+
.component('igzDateTimePicker', {
|
|
23
|
+
bindings: {
|
|
24
|
+
customPresets: '<?',
|
|
25
|
+
clearOption: '<?',
|
|
26
|
+
inputDateFrom: '<',
|
|
27
|
+
inputDateTo: '<?',
|
|
28
|
+
isDateRange: '<',
|
|
29
|
+
isDisabled: '<',
|
|
30
|
+
isRequired: '<?',
|
|
31
|
+
formObject: '<',
|
|
32
|
+
pickFutureDates: '<',
|
|
33
|
+
pickTime: '<',
|
|
34
|
+
presetsList: '<?',
|
|
35
|
+
selectedPreset: '@?',
|
|
36
|
+
inputName: '@',
|
|
37
|
+
onChangeModel: '&'
|
|
38
|
+
},
|
|
39
|
+
templateUrl: 'igz_controls/components/date-time-picker/date-time-picker.tpl.html',
|
|
40
|
+
controller: IgzDateTimePickerController
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* IGZ customization of `angular-bootstrap-date-time-picker` directives:
|
|
45
|
+
* https://github.com/angular-ui/bootstrap/tree/master/src/datepicker
|
|
46
|
+
* https://github.com/angular-ui/bootstrap/tree/master/src/timepicker
|
|
47
|
+
* Bindings properties:
|
|
48
|
+
* inputDateFrom - one way bound value (initial/start date)
|
|
49
|
+
* inputDateTo - one way bound value (end date, not required)
|
|
50
|
+
* isDateRange - boolean parameter (checks if true, then is displayed two calendars)(boolean)
|
|
51
|
+
* isDisabled - boolean parameter (checks if true, input date field is disabled)(boolean)
|
|
52
|
+
* isRequired - boolean parameter (checks if true, input of date is required)(boolean)
|
|
53
|
+
* formObject - one way bound value, form object
|
|
54
|
+
* pickFutureDates - boolean parameter (it allows/disallows to set future dates)
|
|
55
|
+
* pickTime - boolean parameter (checks if true, then is displayed time pickers)
|
|
56
|
+
* selectedOption - string parameter (current selected option from list: last day, etc)
|
|
57
|
+
* inputName - name of input
|
|
58
|
+
* onChangeModel - callback on item added
|
|
59
|
+
*/
|
|
60
|
+
function IgzDateTimePickerController($document, $element, $scope, $timeout, $window, $i18next, i18next, lodash, moment, EventHelperService) {
|
|
61
|
+
var ctrl = this;
|
|
62
|
+
var lng = i18next.language;
|
|
63
|
+
|
|
64
|
+
var defaultTime = {
|
|
65
|
+
hour: 0,
|
|
66
|
+
minute: 0,
|
|
67
|
+
second: 0,
|
|
68
|
+
millisecond: 0
|
|
69
|
+
};
|
|
70
|
+
var defaultTimePart = {
|
|
71
|
+
second: 0,
|
|
72
|
+
millisecond: 0
|
|
73
|
+
};
|
|
74
|
+
var invalidFromDate = false;
|
|
75
|
+
var invalidToDate = false;
|
|
76
|
+
|
|
77
|
+
ctrl.date = {
|
|
78
|
+
from: '',
|
|
79
|
+
to: ''
|
|
80
|
+
};
|
|
81
|
+
ctrl.datepickerOptions = {
|
|
82
|
+
from: {},
|
|
83
|
+
to: {}
|
|
84
|
+
};
|
|
85
|
+
ctrl.displayText = '';
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The preset list in drop-down of date-picker
|
|
89
|
+
* label - the text to display when this preset is selected
|
|
90
|
+
* getRange - a function that gets no arguments and returns an object with `from` and `to` properties
|
|
91
|
+
* representing the date-time range of the preset (`from` or `to` could be omitted, for "open" range)
|
|
92
|
+
* @type {Object.<{label: string, getRange: function}>}
|
|
93
|
+
*/
|
|
94
|
+
ctrl.defaultPresets = {
|
|
95
|
+
hour: {
|
|
96
|
+
label: 'Last hour',
|
|
97
|
+
getRange: function () {
|
|
98
|
+
return {
|
|
99
|
+
from: moment().subtract(1, 'hours')
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
day: {
|
|
104
|
+
label: 'Last day',
|
|
105
|
+
getRange: function () {
|
|
106
|
+
return {
|
|
107
|
+
from: moment().subtract(1, 'days')
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
week: {
|
|
112
|
+
label: 'Last week',
|
|
113
|
+
getRange: function () {
|
|
114
|
+
return {
|
|
115
|
+
from: moment().subtract(1, 'weeks')
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
month: {
|
|
120
|
+
label: 'Last month',
|
|
121
|
+
getRange: function () {
|
|
122
|
+
return {
|
|
123
|
+
from: moment().subtract(1, 'months')
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
year: {
|
|
128
|
+
label: 'Last year',
|
|
129
|
+
getRange: function () {
|
|
130
|
+
return {
|
|
131
|
+
from: moment().subtract(1, 'years')
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
ctrl.isShowDatePicker = false;
|
|
137
|
+
ctrl.isReverted = false;
|
|
138
|
+
ctrl.isPositionCalculated = false;
|
|
139
|
+
ctrl.isDateChanged = false;
|
|
140
|
+
ctrl.isDropdownPositionCalculated = false;
|
|
141
|
+
ctrl.isShowOptionsList = false;
|
|
142
|
+
ctrl.placeholder = '';
|
|
143
|
+
ctrl.presets = {};
|
|
144
|
+
|
|
145
|
+
ctrl.$onInit = onInit;
|
|
146
|
+
ctrl.$onChanges = onChanges;
|
|
147
|
+
ctrl.applyChanges = applyChanges;
|
|
148
|
+
ctrl.cancelChanges = cancelChanges;
|
|
149
|
+
ctrl.clearSelectedDateTime = clearSelectedDateTime;
|
|
150
|
+
ctrl.isOptionSelected = isOptionSelected;
|
|
151
|
+
ctrl.getErrorMessage = getErrorMessage;
|
|
152
|
+
ctrl.showDatepickerPopup = showDatepickerPopup;
|
|
153
|
+
ctrl.showOptionsList = showOptionsList;
|
|
154
|
+
ctrl.onChangeDateTime = onChangeDateTime;
|
|
155
|
+
|
|
156
|
+
//
|
|
157
|
+
// Hook methods
|
|
158
|
+
//
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Initialization method
|
|
162
|
+
*/
|
|
163
|
+
function onInit() {
|
|
164
|
+
if (angular.isDefined(ctrl.customPresets)) {
|
|
165
|
+
ctrl.presets = ctrl.customPresets;
|
|
166
|
+
} else if (angular.isDefined(ctrl.presetsList)) {
|
|
167
|
+
ctrl.presets = ctrl.presetsList.length > 0 ? lodash.pick(ctrl.defaultPresets, ctrl.presetsList) : {};
|
|
168
|
+
} else {
|
|
169
|
+
ctrl.presets = ctrl.defaultPresets;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
ctrl.placeholder = ctrl.isDateRange ? ctrl.pickTime ? 'MMM D, YYYY h:mmA - MMM D, YYYY h:mmA' : 'MMM D, YYYY - MMM D, YYYY' :
|
|
173
|
+
ctrl.pickTime ? 'MMM D, YYYY h:mmA' : 'MMM D, YYYY';
|
|
174
|
+
|
|
175
|
+
if (lodash.has(ctrl.presets, ctrl.selectedPreset)) {
|
|
176
|
+
ctrl.displayText = ctrl.presets[ctrl.selectedPreset].label;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
$scope.$on('info-page-filters_on-apply', onApplyFilters);
|
|
180
|
+
$scope.$on('scrollable-container_on-scrolling', onContainerScrolling);
|
|
181
|
+
|
|
182
|
+
setDatepickerOptions();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* On changes method
|
|
187
|
+
* @param {Object} changes
|
|
188
|
+
*/
|
|
189
|
+
function onChanges(changes) {
|
|
190
|
+
if (angular.isDefined(changes.inputDateFrom)) {
|
|
191
|
+
if (changes.inputDateFrom.currentValue === '' || lodash.isNil(changes.inputDateFrom.currentValue)) {
|
|
192
|
+
ctrl.displayText = '';
|
|
193
|
+
ctrl.date.from = '';
|
|
194
|
+
} else {
|
|
195
|
+
ctrl.date.from = moment(changes.inputDateFrom.currentValue).toDate();
|
|
196
|
+
|
|
197
|
+
if (lodash.has(ctrl.presets, ctrl.selectedPreset)) {
|
|
198
|
+
ctrl.displayText = ctrl.presets[ctrl.selectedPreset].label;
|
|
199
|
+
} else {
|
|
200
|
+
setInputDate();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (angular.isDefined(changes.inputDateTo)) {
|
|
206
|
+
if (changes.inputDateTo.currentValue === '' || lodash.isNil(changes.inputDateTo.currentValue)) {
|
|
207
|
+
ctrl.date.to = '';
|
|
208
|
+
} else {
|
|
209
|
+
ctrl.date.to = moment(changes.inputDateTo.currentValue).toDate();
|
|
210
|
+
|
|
211
|
+
if (lodash.has(ctrl.presets, ctrl.selectedPreset)) {
|
|
212
|
+
ctrl.displayText = ctrl.presets[ctrl.selectedPreset].label;
|
|
213
|
+
} else {
|
|
214
|
+
setInputDate();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
//
|
|
221
|
+
// Public methods
|
|
222
|
+
//
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Applies new date/date range and closes date picker
|
|
226
|
+
*/
|
|
227
|
+
function applyChanges() {
|
|
228
|
+
setDateTime();
|
|
229
|
+
|
|
230
|
+
ctrl.isShowDatePicker = false;
|
|
231
|
+
ctrl.isShowOptionsList = false;
|
|
232
|
+
ctrl.selectedPreset = '';
|
|
233
|
+
|
|
234
|
+
$document.off('click', unselectDropdown);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Cancel changes and closes date picker
|
|
239
|
+
*/
|
|
240
|
+
function cancelChanges() {
|
|
241
|
+
ctrl.isShowDatePicker = false;
|
|
242
|
+
ctrl.isShowOptionsList = false;
|
|
243
|
+
|
|
244
|
+
$document.off('click', unselectDropdown);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Clears selected date-time
|
|
249
|
+
*/
|
|
250
|
+
function clearSelectedDateTime() {
|
|
251
|
+
ctrl.selectedPreset = '';
|
|
252
|
+
ctrl.datepickerOptions = {
|
|
253
|
+
from: {},
|
|
254
|
+
to: {}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
ctrl.onChangeModel({
|
|
258
|
+
newValue: {
|
|
259
|
+
to: null,
|
|
260
|
+
from: null
|
|
261
|
+
},
|
|
262
|
+
selectedPreset: ''
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
ctrl.cancelChanges();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Tests whether the provided preset is selected
|
|
270
|
+
* @param {string} preset
|
|
271
|
+
* @returns {boolean}
|
|
272
|
+
*/
|
|
273
|
+
function isOptionSelected(preset) {
|
|
274
|
+
return ctrl.selectedPreset === preset;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Gets error message for tooltip on 'Apply' button
|
|
279
|
+
* @returns {string}
|
|
280
|
+
*/
|
|
281
|
+
function getErrorMessage() {
|
|
282
|
+
if (ctrl.pickTime && angular.element('.timepicker.from tbody tr').length > 0) {
|
|
283
|
+
var time = {};
|
|
284
|
+
|
|
285
|
+
if (invalidFromDate) {
|
|
286
|
+
var timePickerFromElements = angular.element('.timepicker.from tbody tr').get(1).children;
|
|
287
|
+
var timePickerFromBoxes = {
|
|
288
|
+
hours: timePickerFromElements[0],
|
|
289
|
+
minutes: timePickerFromElements[2]
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
lodash.assign(time, {
|
|
293
|
+
fromHour: angular.element(timePickerFromBoxes.hours).get(0).children[0].value,
|
|
294
|
+
fromMinute: angular.element(timePickerFromBoxes.minutes).get(0).children[0].value
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (invalidToDate && ctrl.isDateRange && angular.element('.timepicker.to tbody tr').length > 0) {
|
|
299
|
+
var timePickerToElements = angular.element('.timepicker.to tbody tr').get(1).children;
|
|
300
|
+
var timePickerToBoxes = {
|
|
301
|
+
hours: timePickerToElements[0],
|
|
302
|
+
minutes: timePickerToElements[2]
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
lodash.assign(time, {
|
|
306
|
+
toHour: angular.element(timePickerToBoxes.hours).get(0).children[0].value,
|
|
307
|
+
toMinute: angular.element(timePickerToBoxes.minutes).get(0).children[0].value
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (invalidFromDate || invalidToDate) {
|
|
312
|
+
return !lodash.every(time, isNumeric) ? $i18next.t('common:ERROR_MSG.DATE_TIME_PICKER.ONLY_DIGITS_ALLOWED', {lng: lng}) :
|
|
313
|
+
isIncorrectTimeFormat(time) ? $i18next.t('common:ERROR_MSG.DATE_TIME_PICKER.12_HOUR_TIME_ALLOWED', {lng: lng}) :
|
|
314
|
+
$i18next.t('common:ERROR_MSG.DATE_TIME_PICKER.FUTURE_DATES_NOT_ALLOWED', {lng: lng});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return !isDateTimeRangeCorrect() ? $i18next.t('common:ERROR_MSG.DATE_TIME_PICKER.TO_LATER_THAN_FROM', {lng: lng}) : '';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Shows options list
|
|
323
|
+
* @param {Event} $event
|
|
324
|
+
*/
|
|
325
|
+
function showOptionsList($event) {
|
|
326
|
+
ctrl.isDropdownPositionCalculated = false;
|
|
327
|
+
ctrl.isDateChanged = false;
|
|
328
|
+
|
|
329
|
+
if (ctrl.isShowDatePicker) {
|
|
330
|
+
ctrl.isShowDatePicker = false;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (ctrl.displayText === '') {
|
|
334
|
+
ctrl.selectedPreset = '';
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (angular.isUndefined($event.keyCode) || $event.keyCode === EventHelperService.ENTER) {
|
|
338
|
+
ctrl.isShowOptionsList = !ctrl.isShowOptionsList;
|
|
339
|
+
|
|
340
|
+
$timeout(function () {
|
|
341
|
+
angular.element($event.target).focus();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
$timeout(showDropdownMenus);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Workaround of native Bootstrap Datepicker behavior
|
|
350
|
+
* which sets focus to popup $element and calculates position of popup
|
|
351
|
+
* @param {Event} $event
|
|
352
|
+
*/
|
|
353
|
+
function showDatepickerPopup($event) {
|
|
354
|
+
var currentDate = moment().utcOffset(0).set(defaultTimePart).toDate();
|
|
355
|
+
|
|
356
|
+
ctrl.isPositionCalculated = false;
|
|
357
|
+
ctrl.isShowOptionsList = false;
|
|
358
|
+
|
|
359
|
+
if (!ctrl.pickFutureDates) {
|
|
360
|
+
ctrl.datepickerOptions.from.maxDate = currentDate;
|
|
361
|
+
ctrl.datepickerOptions.to.maxDate = currentDate;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
ctrl.date.from = lodash.isNil(ctrl.inputDateFrom) || ctrl.inputDateFrom === '' ||
|
|
365
|
+
!lodash.isEmpty(ctrl.selectedPreset) ? currentDate :
|
|
366
|
+
moment(ctrl.inputDateFrom).toDate();
|
|
367
|
+
|
|
368
|
+
ctrl.date.to = lodash.isNil(ctrl.inputDateTo) || ctrl.inputDateTo === '' ||
|
|
369
|
+
!lodash.isEmpty(ctrl.selectedPreset) ? currentDate :
|
|
370
|
+
moment(ctrl.inputDateTo).toDate();
|
|
371
|
+
|
|
372
|
+
if (angular.isUndefined($event.keyCode) || $event.keyCode === EventHelperService.ENTER) {
|
|
373
|
+
ctrl.isShowDatePicker = !ctrl.isShowDatePicker;
|
|
374
|
+
|
|
375
|
+
$timeout(function () {
|
|
376
|
+
angular.element($event.target).focus();
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
$timeout(showDropdownMenus);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (!ctrl.isDateRange) {
|
|
383
|
+
$document.on('click', unselectDropdown);
|
|
384
|
+
$document.on('keyup', onKeyUp);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Checks date sequence and sets default date ranges
|
|
390
|
+
* @param {string} [preset=''] selected preset from dropdown list
|
|
391
|
+
*/
|
|
392
|
+
function onChangeDateTime(preset) {
|
|
393
|
+
ctrl.selectedPreset = '';
|
|
394
|
+
ctrl.isDateChanged = true;
|
|
395
|
+
|
|
396
|
+
if (lodash.has(ctrl.presets, preset)) {
|
|
397
|
+
ctrl.isShowOptionsList = false;
|
|
398
|
+
ctrl.selectedPreset = preset;
|
|
399
|
+
|
|
400
|
+
ctrl.date = ctrl.presets[preset].getRange();
|
|
401
|
+
|
|
402
|
+
$document.off('click', unselectDropdown);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (!ctrl.pickTime) {
|
|
406
|
+
var timeZoneOffset = moment(ctrl.date.from).utcOffset() * 60 * 1000;
|
|
407
|
+
ctrl.date.from = moment(ctrl.date.from).set(defaultTime).add(timeZoneOffset, 'milliseconds').toDate();
|
|
408
|
+
|
|
409
|
+
if (ctrl.isDateRange && angular.isDefined(ctrl.date.to)) {
|
|
410
|
+
timeZoneOffset = moment(ctrl.date.to).utcOffset() * 60 * 1000;
|
|
411
|
+
ctrl.date.to = moment(ctrl.date.to).set(defaultTime).add(timeZoneOffset, 'milliseconds').toDate();
|
|
412
|
+
}
|
|
413
|
+
} else if (angular.element('.timepicker.from tbody tr').length > 0) {
|
|
414
|
+
var timePickerFromElements = angular.element('.timepicker.from tbody tr').get(1).children;
|
|
415
|
+
var timePickerFromBoxes = {
|
|
416
|
+
hours: timePickerFromElements[0],
|
|
417
|
+
minutes: timePickerFromElements[2]
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
if (moment(ctrl.date.from).isAfter(ctrl.datepickerOptions.from.maxDate) || lodash.isNull(ctrl.date.from)) {
|
|
421
|
+
angular.element(timePickerFromBoxes.hours).addClass('invalid');
|
|
422
|
+
angular.element(timePickerFromBoxes.minutes).addClass('invalid');
|
|
423
|
+
|
|
424
|
+
invalidFromDate = true;
|
|
425
|
+
} else {
|
|
426
|
+
angular.element(timePickerFromBoxes.hours).removeClass('invalid');
|
|
427
|
+
angular.element(timePickerFromBoxes.minutes).removeClass('invalid');
|
|
428
|
+
|
|
429
|
+
invalidFromDate = false;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (ctrl.isDateRange) {
|
|
433
|
+
var timePickerToElements = angular.element('.timepicker.to tbody tr').get(1).children;
|
|
434
|
+
var timePickerToBoxes = {
|
|
435
|
+
hours: timePickerToElements[0],
|
|
436
|
+
minutes: timePickerToElements[2]
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
if (moment(ctrl.date.to).isAfter(ctrl.datepickerOptions.to.maxDate) || lodash.isNull(ctrl.date.to)) {
|
|
440
|
+
angular.element(timePickerToBoxes.hours).addClass('invalid');
|
|
441
|
+
angular.element(timePickerToBoxes.minutes).addClass('invalid');
|
|
442
|
+
|
|
443
|
+
invalidToDate = true;
|
|
444
|
+
} else {
|
|
445
|
+
angular.element(timePickerToBoxes.hours).removeClass('invalid');
|
|
446
|
+
angular.element(timePickerToBoxes.minutes).removeClass('invalid');
|
|
447
|
+
|
|
448
|
+
invalidToDate = false;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (angular.isDefined(preset)) {
|
|
454
|
+
setDateTime(preset);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
//
|
|
459
|
+
// Private method
|
|
460
|
+
//
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Checks is string value is a number contains with digits only
|
|
464
|
+
* @param {string} value
|
|
465
|
+
* @returns {boolean}
|
|
466
|
+
*/
|
|
467
|
+
function isNumeric(value) {
|
|
468
|
+
return /^\d+$/.test(value);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Checks if time format is incorrect
|
|
473
|
+
* @param {Object} time
|
|
474
|
+
* @returns {boolean}
|
|
475
|
+
*/
|
|
476
|
+
function isIncorrectTimeFormat(time) {
|
|
477
|
+
return invalidFromDate && !isCorrectTime(Number(time.fromHour), Number(time.fromMinute)) ||
|
|
478
|
+
invalidToDate && !isCorrectTime(Number(time.toHour), Number(time.toMinute));
|
|
479
|
+
|
|
480
|
+
// checks if 01 < hour < 12 and 00 < minute < 59 or not (12-hour time format)
|
|
481
|
+
function isCorrectTime(hour, minute) {
|
|
482
|
+
var hourRange = {
|
|
483
|
+
max: 13,
|
|
484
|
+
min: 1
|
|
485
|
+
};
|
|
486
|
+
var minuteRange = {
|
|
487
|
+
max: 60,
|
|
488
|
+
min: 0
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
return lodash.inRange(hour, hourRange.min, hourRange.max) && lodash.inRange(minute, minuteRange.min, minuteRange.max);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Returns boolean value depending on whether there is a range correct/incorrect
|
|
497
|
+
*/
|
|
498
|
+
function isDateTimeRangeCorrect() {
|
|
499
|
+
return !ctrl.isDateRange ||
|
|
500
|
+
!lodash.isNil(ctrl.date.from) && !lodash.isNil(ctrl.date.to) &&
|
|
501
|
+
moment(ctrl.date.from).isBefore(ctrl.date.to);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Sets changed date-time to input field
|
|
506
|
+
*/
|
|
507
|
+
function setInputDate() {
|
|
508
|
+
var dateFrom = moment(ctrl.date.from).format('MMM D, YYYY') + (ctrl.pickTime ? moment(ctrl.date.from).format(' h:mmA') : '');
|
|
509
|
+
var dateTo = moment(ctrl.date.to).format('MMM D, YYYY') + (ctrl.pickTime ? moment(ctrl.date.to).format(' h:mmA') : '');
|
|
510
|
+
|
|
511
|
+
ctrl.displayText = dateFrom + (ctrl.isDateRange ? ' - ' + dateTo : '');
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Sets datepicker options
|
|
516
|
+
*/
|
|
517
|
+
function setDatepickerOptions() {
|
|
518
|
+
ctrl.datepickerOptions = {
|
|
519
|
+
from: {
|
|
520
|
+
showWeeks: false,
|
|
521
|
+
maxDate: null,
|
|
522
|
+
maxMode: 'day',
|
|
523
|
+
formatDayTitle: (ctrl.isDateRange ? 'Fro\'m\':' : ' ').toString() + ' MMMM yyyy'
|
|
524
|
+
},
|
|
525
|
+
to: {
|
|
526
|
+
showWeeks: false,
|
|
527
|
+
maxDate: null,
|
|
528
|
+
maxMode: 'day',
|
|
529
|
+
formatDayTitle: (ctrl.isDateRange ? 'To:' : ' ').toString() + ' MMMM yyyy'
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Recalculates date on applying filters
|
|
536
|
+
*/
|
|
537
|
+
function onApplyFilters() {
|
|
538
|
+
if (!lodash.isEmpty(ctrl.selectedPreset)) {
|
|
539
|
+
onChangeDateTime(ctrl.selectedPreset);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Calculates position of dropdown menus and closes menus if date-picker input is not visible on scrolling
|
|
545
|
+
*/
|
|
546
|
+
function onContainerScrolling() {
|
|
547
|
+
var datePickerDropdownElement = ctrl.isShowDatePicker ? angular.element($element.find('.date-time-pickers')) :
|
|
548
|
+
ctrl.isShowOptionsList ? angular.element($element.find('.options-dropdown')) : null;
|
|
549
|
+
|
|
550
|
+
$timeout(showDropdownMenus);
|
|
551
|
+
|
|
552
|
+
if (!lodash.isEmpty(datePickerDropdownElement)) {
|
|
553
|
+
$timeout(function () {
|
|
554
|
+
var pageWrapper = $element.closest('.igz-scrollable-container');
|
|
555
|
+
|
|
556
|
+
if (pageWrapper.length !== 0 && pageWrapper[0].getBoundingClientRect().top > datePickerDropdownElement[0].offsetTop && !ctrl.isReverted) {
|
|
557
|
+
unselectDropdown();
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Key Up Callback
|
|
565
|
+
* @param {Object} event - native event object
|
|
566
|
+
*/
|
|
567
|
+
function onKeyUp(event) {
|
|
568
|
+
|
|
569
|
+
// close date picker via ESC button
|
|
570
|
+
if (event.keyCode === EventHelperService.ESCAPE) {
|
|
571
|
+
unselectDropdown();
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Handle click on the document and not on the datepicker and close the datepicker
|
|
577
|
+
* @param {Event} [e] - event
|
|
578
|
+
*/
|
|
579
|
+
function unselectDropdown(e) {
|
|
580
|
+
if (angular.isUndefined(e) || $element.find(e.currentTarget.activeElement).length === 0) {
|
|
581
|
+
$scope.$evalAsync(function () {
|
|
582
|
+
ctrl.isShowDatePicker = false;
|
|
583
|
+
ctrl.isShowOptionsList = false;
|
|
584
|
+
|
|
585
|
+
$document.off('click', unselectDropdown);
|
|
586
|
+
$document.off('keyup', onKeyUp);
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Calculates position of options dropdown and date-picker menu
|
|
593
|
+
*/
|
|
594
|
+
function showDropdownMenus() {
|
|
595
|
+
var datePickerDropdownElement = ctrl.isShowDatePicker ? angular.element($element.find('.date-time-pickers')) :
|
|
596
|
+
ctrl.isShowOptionsList ? angular.element($element.find('.options-dropdown')) : null;
|
|
597
|
+
var datePickerDropdownParent = angular.element($element.find('.date-time-picker'));
|
|
598
|
+
var headerElement = angular.element('.igz-main-header');
|
|
599
|
+
|
|
600
|
+
if (!lodash.isEmpty(datePickerDropdownElement) && !lodash.isEmpty(datePickerDropdownParent)) {
|
|
601
|
+
var elementHeight = datePickerDropdownElement[0].clientHeight;
|
|
602
|
+
var parentHeight = datePickerDropdownParent[0].clientHeight;
|
|
603
|
+
var parentTop = datePickerDropdownParent[0].getBoundingClientRect().top;
|
|
604
|
+
var parentLeft = datePickerDropdownParent[0].getBoundingClientRect().left;
|
|
605
|
+
var roomAbove = parentTop - headerElement[0].clientHeight;
|
|
606
|
+
|
|
607
|
+
// if there is not enough bottom room to put options dropdown it is necessary to put options dropdown to top
|
|
608
|
+
if (ctrl.isShowOptionsList) {
|
|
609
|
+
if ($window.innerHeight - parentTop - parentHeight < elementHeight && roomAbove >= elementHeight) {
|
|
610
|
+
ctrl.isReverted = true;
|
|
611
|
+
datePickerDropdownElement.css('top', parentTop - elementHeight);
|
|
612
|
+
} else {
|
|
613
|
+
ctrl.isReverted = false;
|
|
614
|
+
datePickerDropdownElement.css('top', parentTop + parentHeight);
|
|
615
|
+
}
|
|
616
|
+
datePickerDropdownElement.css('left', parentLeft);
|
|
617
|
+
datePickerDropdownElement.css('width', datePickerDropdownParent[0].clientWidth);
|
|
618
|
+
|
|
619
|
+
ctrl.isDropdownPositionCalculated = true;
|
|
620
|
+
$document.on('click', unselectDropdown);
|
|
621
|
+
$document.on('keyup', onKeyUp);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (ctrl.isShowDatePicker) {
|
|
625
|
+
lodash.forEach(angular.element('.date-time-pickers th small'), function (label) {
|
|
626
|
+
label.textContent = label.textContent.slice(0, 1);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
var hasEnoughTopRoom = roomAbove >= elementHeight;
|
|
630
|
+
|
|
631
|
+
// if there is not enough bottom room to put date-picker it is necessary to check
|
|
632
|
+
// if there is enough top room to put date-picker. If not - to set date-picker's top position under header
|
|
633
|
+
if ($window.innerHeight - parentTop - parentHeight < elementHeight) {
|
|
634
|
+
ctrl.isReverted = true;
|
|
635
|
+
datePickerDropdownElement.css('top', hasEnoughTopRoom ?
|
|
636
|
+
parentTop - elementHeight :
|
|
637
|
+
headerElement[0].getBoundingClientRect().bottom);
|
|
638
|
+
} else {
|
|
639
|
+
ctrl.isReverted = false;
|
|
640
|
+
datePickerDropdownElement.css('top', parentTop + parentHeight);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
if ($window.innerWidth - parentLeft < datePickerDropdownElement[0].clientWidth) {
|
|
644
|
+
var rightPosition = $window.innerWidth - datePickerDropdownParent[0].getBoundingClientRect().right;
|
|
645
|
+
datePickerDropdownElement.css('right', rightPosition > 0 ? rightPosition : 0);
|
|
646
|
+
} else {
|
|
647
|
+
datePickerDropdownElement.css('left', parentLeft);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
ctrl.isPositionCalculated = true;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Sets date and time to input field in format 'MMM D, h:mmA'
|
|
657
|
+
* @param {string} [preset=''] selected preset from dropdown list
|
|
658
|
+
*/
|
|
659
|
+
function setDateTime(preset) {
|
|
660
|
+
if (!lodash.isNil(ctrl.date.from)) {
|
|
661
|
+
var newValue = {
|
|
662
|
+
from: ctrl.pickTime ? moment(ctrl.date.from).set(defaultTimePart).toDate() : moment(ctrl.date.from).utcOffset(0).set(defaultTime).toDate()
|
|
663
|
+
};
|
|
664
|
+
ctrl.inputDateFrom = ctrl.date.from;
|
|
665
|
+
|
|
666
|
+
setInputDate();
|
|
667
|
+
|
|
668
|
+
if (!lodash.isNil(ctrl.date.to) && moment(ctrl.date.from).isBefore(ctrl.date.to)) {
|
|
669
|
+
ctrl.inputDateTo = ctrl.date.to;
|
|
670
|
+
|
|
671
|
+
setInputDate();
|
|
672
|
+
|
|
673
|
+
newValue.to = ctrl.pickTime ? moment(ctrl.date.to).set(defaultTimePart).toDate() : moment.utc(ctrl.date.to).set(defaultTime).toDate();
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (lodash.has(ctrl.presets, preset)) {
|
|
677
|
+
ctrl.displayText = ctrl.presets[preset].label;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
if (angular.isFunction(ctrl.onChangeModel)) {
|
|
681
|
+
ctrl.onChangeModel({
|
|
682
|
+
newValue: ctrl.isDateRange ? newValue : newValue.from,
|
|
683
|
+
selectedPreset: ctrl.selectedPreset
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}());
|