diff --git a/src/directive.ts b/src/directive.ts index 2aca70f..49facbf 100644 --- a/src/directive.ts +++ b/src/directive.ts @@ -301,7 +301,10 @@ export default class Directive implements ng.IDirective { $scope.input.attr('tabindex', 0); ($scope.position || '').split(' ').forEach((className: string) => $scope.picker.addClass(className)); if (!$scope.inline) $scope.picker[0].parentNode.removeChild($scope.picker[0]); - else $scope.picker.addClass('inline'); + else { + $element.after($scope.picker); + $scope.picker.addClass('inline'); + } // transclude scope to template additions this.$timeout(() => { diff --git a/src/index.less b/src/index.less index 41c6ca3..666e905 100644 --- a/src/index.less +++ b/src/index.less @@ -20,7 +20,8 @@ @selected-bg-image: linear-gradient(#45b1e8, #3097de); @selected-border-color: #3ca0dd; -.moment-picker-reference { cursor: pointer; } +.moment-picker-reference, +.moment-picker-input { cursor: pointer; } .moment-picker { position: absolute; z-index: 1000; diff --git a/tests/elementCreation.ts b/tests/elementCreation.ts index 9bef544..8885149 100644 --- a/tests/elementCreation.ts +++ b/tests/elementCreation.ts @@ -7,44 +7,29 @@ describe('Element creation', () => { test.bootstrap(); // creating directive - it('should create a .moment-picker element that transclude content', () => { + it('should create a `.moment-picker-reference` element that transclude content', () => { let $element = test.buildTemplate('div', { class: 'my-content' }), - $children = [], content; expect($element).toBeDefined(); - expect($element.hasClass('moment-picker')).toBe(true); - - // it should have 2 children - expect($element.children().length).toEqual(2); - angular.forEach($element.children(), (element: ng.IAugmentedJQuery) => $children.push(angular.element(element))); - - // first child contains transcluded content - expect($children[0].hasClass('moment-picker-contents')).toBe(true); - content = $children[0].children(); - expect(content.length).toEqual(1); - expect(angular.element(content[0]).hasClass('my-content')).toBe(true); - - // second child contains picker container - expect($children[1].hasClass('moment-picker-container')).toBe(true); + expect($element.hasClass('moment-picker-reference')).toBe(true); + expect($element.hasClass('my-content')).toBe(true); }); // check transcluded DIV content it('should transclude DIV content', () => { - let $element = test.buildTemplate('div', { class: 'my-content' }, 'My content'), - $contents = $element.find('.moment-picker-contents').children(); + let $element = test.buildTemplate('div', { class: 'my-content' }, 'My content'); - expect($contents.length).toEqual(1); - expect(angular.element($contents[0]).hasClass('my-content')).toBe(true); - expect(angular.element($contents[0]).text()).toEqual('My content'); + expect($element.length).toEqual(1); + expect(angular.element($element[0]).hasClass('my-content')).toBe(true); + expect(angular.element($element[0]).text()).toEqual('My content'); }); // check transcluded INPUT content it('should transclude INPUT content', () => { - let $element = test.buildTemplate('input', { class: 'my-content' }), - $contents = $element.find('.moment-picker-contents').children(); + let $element = test.buildTemplate('input', { class: 'my-content' }); - expect($contents.length).toEqual(1); - expect(angular.element($contents[0]).hasClass('my-content')).toBe(true); + expect($element.length).toEqual(1); + expect(angular.element($element[0]).hasClass('my-content')).toBe(true); }); }); diff --git a/tests/openClosePicker.ts b/tests/openClosePicker.ts index ec5f088..923a336 100644 --- a/tests/openClosePicker.ts +++ b/tests/openClosePicker.ts @@ -3,9 +3,7 @@ import * as test from './utility'; describe('Open / close picker', () => { - let $inputPicker: ng.IAugmentedJQuery; let $inputContent: ng.IAugmentedJQuery; - let $divPicker: ng.IAugmentedJQuery; let $divContent: ng.IAugmentedJQuery; // init test @@ -14,52 +12,50 @@ describe('Open / close picker', () => { // create two pickers for all tests beforeEach(() => { // tslint:disable-next-line:no-unused-expression - $inputPicker = test.buildTemplate('input', { class: 'input-picker' }); - $inputContent = $inputPicker.find('.moment-picker-input'); - $divPicker = test.buildTemplate('div', { class: 'div-picker' }); - $divContent = $divPicker.find('.moment-picker-input'); + $inputContent = test.buildTemplate('input', { class: 'input-picker' }); + $divContent = test.buildTemplate('div', { class: 'div-picker' }); }); - const isVisible = ($element: ng.IAugmentedJQuery) => !$element.find('.moment-picker-container').hasClass('ng-hide'); + const isVisible = ($element: ng.IAugmentedJQuery) => test.getPicker($element).is(':visible'); // open picker on click it('should open the picker on click', () => { test.trigger($inputContent, 'click'); - expect(isVisible($inputPicker)).toBe(true); + expect(isVisible($inputContent)).toBe(true); test.trigger($divContent, 'click'); - expect(isVisible($divPicker)).toBe(true); + expect(isVisible($divContent)).toBe(true); }); // open picker on focus // it('should open the picker on focus', () => { // test.trigger($inputContent, 'focus'); - // expect(isVisible($inputPicker)).toBe(true); + // expect(isVisible($inputContent)).toBe(true); // test.trigger($divContent, 'focus'); - // expect(isVisible($divPicker)).toBe(true); + // expect(isVisible($divContent)).toBe(true); // }); // close picker on blur it('should close the picker on blur', () => { test.trigger($inputContent, 'click'); - expect(isVisible($inputPicker)).toBe(true); + expect(isVisible($inputContent)).toBe(true); test.trigger($inputContent, 'blur'); - expect(isVisible($inputPicker)).toBe(false); + expect(isVisible($inputContent)).toBe(false); test.trigger($divContent, 'click'); - expect(isVisible($divPicker)).toBe(true); + expect(isVisible($divContent)).toBe(true); test.trigger($divContent, 'blur'); - expect(isVisible($divPicker)).toBe(false); + expect(isVisible($divContent)).toBe(false); }); // close picker clicking on another one it('should close a picker when clicking to another picker', () => { test.trigger($inputContent, 'click'); - expect(isVisible($inputPicker)).toBe(true); + expect(isVisible($inputContent)).toBe(true); test.trigger($divContent, 'click'); - expect(isVisible($divPicker)).toBe(true); - expect(isVisible($inputPicker)).toBe(false); + expect(isVisible($divContent)).toBe(true); + expect(isVisible($inputContent)).toBe(false); }); }); diff --git a/tests/properties/isOpen.ts b/tests/properties/isOpen.ts index 58fc791..1de2143 100644 --- a/tests/properties/isOpen.ts +++ b/tests/properties/isOpen.ts @@ -14,7 +14,7 @@ describe('Property `isOpen`', () => { $rootScope = _$rootScope_; })); - const isVisible = ($element: ng.IAugmentedJQuery) => !$element.find('.moment-picker-container').hasClass('ng-hide'); + const isVisible = ($element: ng.IAugmentedJQuery) => test.getPicker($element).is(':visible'); it('should open the picker when set to `true`', () => { let $picker = test.buildTemplate('input', { isOpen: true }); diff --git a/tests/properties/keyboard.ts b/tests/properties/keyboard.ts index 43f0a95..1af183b 100644 --- a/tests/properties/keyboard.ts +++ b/tests/properties/keyboard.ts @@ -42,7 +42,7 @@ describe('Keyboard', () => { let $input: ng.IAugmentedJQuery; beforeEach(() => { - $input = test.buildTemplate('input', { keyboard: 'true', class: 'input-picker' }).find('.input-picker'); + $input = test.buildTemplate('input', { keyboard: 'true' }); }); // prevent default event @@ -63,14 +63,12 @@ describe('Keyboard', () => { }); describe('picker open/close', () => { - let $picker: ng.IAugmentedJQuery; let $input: ng.IAugmentedJQuery; - const isOpen = () => !$picker.find('.moment-picker-container').hasClass('ng-hide'); + const isOpen = () => test.getPicker($input).is(':visible'); beforeEach(inject(($rootScope) => { - $picker = test.buildTemplate('input', { keyboard: 'true', class: 'input-picker' }); - $input = $picker.find('.input-picker'); + $input = test.buildTemplate('input', { keyboard: 'true' }); })); // close picker on pressing ESC @@ -105,7 +103,7 @@ describe('Keyboard', () => { const pickerViews = ['decade', 'year', 'month', 'day', 'hour', 'minute']; const commonOpts = { keyboard: 'true', ngModel: 'date', format: 'YYYY-MM-DD HH:mm:ss', class: 'input-picker', locale: locale }; - const getHighlightedText = ($element: ng.IAugmentedJQuery) => $element.find('.moment-picker-container td.highlighted').text(); + const getHighlightedText = ($element: ng.IAugmentedJQuery) => test.getPicker($element).find('td.highlighted').text(); // get formats from momentPickerProvider beforeEach(inject(($rootScope: ng.IRootScopeService, momentPicker: IProviderOptions) => { // tslint:disable-line:variable-name @@ -138,9 +136,9 @@ describe('Keyboard', () => { // highlight on open it('should highlight the selected ' + view + ' on picker open', () => { let options = angular.extend({ startView: view }, commonOpts), - $picker = test.buildTemplate('input', options, undefined, $scope); + $input = test.buildTemplate('input', options, undefined, $scope); - expect(getHighlightedText($picker)).toBe(date.format(formats[view])); + expect(getHighlightedText($input)).toBe(date.format(formats[view])); }); // highlight on key press @@ -151,12 +149,11 @@ describe('Keyboard', () => { it(title, () => { let options = angular.extend({ startView: view }, commonOpts), - $picker = test.buildTemplate('input', options, undefined, $scope), - $input = $picker.find('.input-picker'), + $input = test.buildTemplate('input', options, undefined, $scope), finalDate = date.clone()[operation](datesToShift, viewPrecision); sendKey($input, key); - expect(getHighlightedText($picker)).toBe(finalDate.format(formats[view])); + expect(getHighlightedText($input)).toBe(finalDate.format(formats[view])); }); }); }); diff --git a/tests/properties/locale.ts b/tests/properties/locale.ts index 791b2fc..ba3f29a 100644 --- a/tests/properties/locale.ts +++ b/tests/properties/locale.ts @@ -35,20 +35,20 @@ describe('Property `locale`', () => { expectedHeaders.hour [locale] = localeDate.startOf('hour').format('lll'); }); - const getHeader = ($element: ng.IAugmentedJQuery) => Array.prototype.slice.call($element.find('.moment-picker-container th'), 0) + const getHeader = ($element: ng.IAugmentedJQuery) => Array.prototype.slice.call(test.getPicker($element).find('th'), 0) .map((e: Node) => e.textContent) .filter((s: string) => s != '←' && s != '→') .join(stringDivider); it('should change locale dinamically', () => { angular.forEach(expectedHeaders, (header, view: string) => { - let $scope = $rootScope.$new(), - $picker = test.buildTemplate('input', { locale: '\{\{locale\}\}', format: format, startView: view, startDate: startDate }, undefined, $scope); + let $scope = $rootScope.$new(), + $input = test.buildTemplate('input', { locale: '\{\{locale\}\}', format: format, startView: view, startDate: startDate }, undefined, $scope); angular.forEach(header, (expectedHeader: string, locale: string) => { $scope['locale'] = locale; $scope.$apply(); - expect(getHeader($picker)).toBe(expectedHeader); + expect(getHeader($input)).toBe(expectedHeader); }); }); }); diff --git a/tests/properties/startDate.ts b/tests/properties/startDate.ts index 7f2c2ab..4733a31 100644 --- a/tests/properties/startDate.ts +++ b/tests/properties/startDate.ts @@ -19,7 +19,7 @@ describe('Property `startDate`', () => { // init test test.bootstrap(); - const getHeaderText = ($element: ng.IAugmentedJQuery) => angular.element($element.find('.header-view th')[1]).text(); + const getHeaderText = ($element: ng.IAugmentedJQuery) => angular.element(test.getPicker($element).find('.header-view th')[1]).text(); // test all views angular.forEach(expectedHeaders, (expectedHeader, view) => { @@ -27,8 +27,8 @@ describe('Property `startDate`', () => { title = 'should open ' + viewName + ' View in ' + expectedHeader; it(title, () => { - let $propAsMoment = test.buildTemplate('div', { locale: 'en', format: format, startView: view, startDate: startDate }), - $propAsString = test.buildTemplate('div', { locale: 'en', format: format, startView: view, startDate: startDateStr }); + let $propAsMoment = test.buildTemplate('div', { locale: 'en', format: format, startView: view, startDate: startDate }), + $propAsString = test.buildTemplate('div', { locale: 'en', format: format, startView: view, startDate: startDateStr }); // Moment object input expect(getHeaderText($propAsMoment)).toBe(expectedHeader); diff --git a/tests/utility.ts b/tests/utility.ts index 66221a4..75aafba 100644 --- a/tests/utility.ts +++ b/tests/utility.ts @@ -1,4 +1,5 @@ import * as angular from 'angular'; +import { IDirectiveScopeInternal } from '../src/definitions'; let $compile, $timeout, $rootScope; @@ -56,6 +57,8 @@ export const buildTemplate = (tag: string, options?: any, content?: any, $scope? return $element; }; +export const getPicker = (element: ng.IAugmentedJQuery) => (element.isolateScope()).picker; + // wrap jquery trigger fn: event trigger + digest stimulation export const trigger = (element: ng.IAugmentedJQuery, event: string | JQueryEventObject) => { // use jquey trigger method to propagate event to parent nodes diff --git a/tests/value.ts b/tests/value.ts index 8389d16..2e30936 100644 --- a/tests/value.ts +++ b/tests/value.ts @@ -13,7 +13,7 @@ describe('Value', () => { // same picker settings for all tests in this suite beforeEach(inject(($rootScope: ng.IRootScopeService) => { $scope = $rootScope.$new(); - $input = test.buildTemplate('input', { momentPicker: 'dateStr', ngModel: 'dateObj', format: format, class: 'input-picker' }, undefined, $scope).find('.input-picker'); + $input = test.buildTemplate('input', { momentPicker: 'dateStr', ngModel: 'dateObj', format: format }, undefined, $scope); })); // set Model Value from View Value @@ -77,7 +77,7 @@ describe('Value', () => { let date = moment('2017-01-12', format); $scope['date'] = date; - $input = test.buildTemplate('input', { momentPicker: 'date', ngModel: 'date', format: format, class: 'input-picker' }, undefined, $scope).find('.input-picker'); + $input = test.buildTemplate('input', { momentPicker: 'date', ngModel: 'date', format: format }, undefined, $scope); expect($scope['date'].isSame(date)).toBe(true); expect($input.val()).toBe(date.format(format)); }); @@ -86,8 +86,8 @@ describe('Value', () => { it('should sync model updates across pickers', () => { let dateFormat = 'YYYY-MM-DD', timeFormat = 'HH:mm', - $date = test.buildTemplate('input', { momentPicker: 'date', ngModel: 'datetime', format: dateFormat, class: 'date-picker' }, undefined, $scope).find('.date-picker'), - $time = test.buildTemplate('input', { momentPicker: 'time', ngModel: 'datetime', format: timeFormat, class: 'time-picker' }, undefined, $scope).find('.time-picker'); + $date = test.buildTemplate('input', { momentPicker: 'date', ngModel: 'datetime', format: dateFormat }, undefined, $scope), + $time = test.buildTemplate('input', { momentPicker: 'time', ngModel: 'datetime', format: timeFormat }, undefined, $scope); $scope['datetime'] = moment('2017-01-12 20:32', dateFormat + ' ' + timeFormat); $scope.$digest();