iguazio.dashboard-controls 1.0.12 → 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.
Files changed (26) hide show
  1. package/dist/i18n/en/common.json +15 -2
  2. package/dist/i18n/en/functions.json +2 -1
  3. package/dist/js/iguazio.dashboard-controls.js +14051 -12665
  4. package/dist/less/iguazio.dashboard-controls.less +2814 -2265
  5. package/package.json +1 -1
  6. package/src/i18n/en/common.json +15 -2
  7. package/src/i18n/en/functions.json +2 -1
  8. package/src/igz_controls/components/date-time-picker/date-time-picker.component.js +689 -0
  9. package/src/igz_controls/components/date-time-picker/date-time-picker.component.spec.js +356 -0
  10. package/src/igz_controls/components/date-time-picker/date-time-picker.less +418 -0
  11. package/src/igz_controls/components/date-time-picker/date-time-picker.tpl.html +90 -0
  12. package/src/igz_controls/components/date-time-picker/prevent-parent-scroll.directive.js +27 -0
  13. package/src/igz_controls/components/log-table-row/log-table-row.component.js +57 -0
  14. package/src/igz_controls/components/log-table-row/log-table-row.component.spec.js +49 -0
  15. package/src/igz_controls/components/log-table-row/log-table-row.less +29 -0
  16. package/src/igz_controls/components/log-table-row/log-table-row.tpl.html +16 -0
  17. package/src/igz_controls/components/multiple-checkboxes/multiple-checkboxes.component.js +39 -5
  18. package/src/igz_controls/services/control-panel-logs-data.service.js +203 -0
  19. package/src/nuclio/common/components/deploy-log/deploy-log.component.js +1 -1
  20. package/src/nuclio/common/screens/create-function/function-from-scratch/function-from-scratch.component.js +0 -14
  21. package/src/nuclio/common/screens/create-function/function-from-template/function-from-template.component.js +0 -14
  22. package/src/nuclio/common/services/export.service.js +28 -5
  23. package/src/nuclio/functions/version/version-execution-log/version-execution-log.component.js +463 -0
  24. package/src/nuclio/functions/version/version-execution-log/version-execution-log.less +99 -0
  25. package/src/nuclio/functions/version/version-execution-log/version-execution-log.tpl.html +177 -0
  26. 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
+ }());