/* global document */ 'use strict'; import CMS, { Helpers, KEYS } from '../../../static/cms/js/modules/cms.base'; import Modal from '../../../static/cms/js/modules/cms.modal'; import $ from 'jquery'; import { rewire, resetRewire } from './helpers/rewire'; vi.mock('../../../static/cms/js/modules/loader', async () => { const { lazyMock, registerActual } = await import('./helpers/rewire'); registerActual('loader', await vi.importActual('../../../static/cms/js/modules/loader')); return lazyMock('loader', { showLoader: 'showLoader', hideLoader: 'hideLoader' }); }); var showLoader; var hideLoader; window.CMS = CMS; CMS.Modal = Modal; describe('CMS.Modal', function() { fixture.setBase('cms/tests/frontend/unit/fixtures'); beforeEach(() => { showLoader = jasmine.createSpy(); hideLoader = jasmine.createSpy(); rewire('showLoader', showLoader); rewire('hideLoader', hideLoader); CMS._eventRoot = $('#cms-top'); CMS.ChangeTracker = function() { return { isFormChanged: function() { return false; } }; }; }); afterEach(() => { resetRewire('showLoader'); resetRewire('hideLoader'); }); it('creates a Modal class', function() { expect(CMS.Modal).toBeDefined(); }); it('has public API', function() { expect(CMS.Modal.prototype.open).toEqual(jasmine.any(Function)); expect(CMS.Modal.prototype.close).toEqual(jasmine.any(Function)); expect(CMS.Modal.prototype.minimize).toEqual(jasmine.any(Function)); expect(CMS.Modal.prototype.maximize).toEqual(jasmine.any(Function)); expect(CMS.Modal._setupCtrlEnterSave).toEqual(jasmine.any(Function)); }); describe('instance', function() { it('has ui', function(done) { $(function() { var modal = new CMS.Modal(); expect(modal.ui).toEqual(jasmine.any(Object)); expect(Object.keys(modal.ui)).toContain('modal'); expect(Object.keys(modal.ui)).toContain('body'); expect(Object.keys(modal.ui)).toContain('window'); expect(Object.keys(modal.ui)).toContain('toolbarLeftPart'); expect(Object.keys(modal.ui)).toContain('minimizeButton'); expect(Object.keys(modal.ui)).toContain('maximizeButton'); expect(Object.keys(modal.ui)).toContain('title'); expect(Object.keys(modal.ui)).toContain('titlePrefix'); expect(Object.keys(modal.ui)).toContain('titleSuffix'); expect(Object.keys(modal.ui)).toContain('resize'); expect(Object.keys(modal.ui)).toContain('breadcrumb'); expect(Object.keys(modal.ui)).toContain('closeAndCancel'); expect(Object.keys(modal.ui)).toContain('modalButtons'); expect(Object.keys(modal.ui)).toContain('modalBody'); expect(Object.keys(modal.ui)).toContain('frame'); expect(Object.keys(modal.ui)).toContain('shim'); expect(Object.keys(modal.ui).length).toEqual(16); done(); }); }); it('has options', function(done) { $(function() { var modal = new CMS.Modal(); expect(modal.options).toEqual({ onClose: false, minHeight: 400, minWidth: 800, modalDuration: 200, resizable: true, maximizable: true, minimizable: true, closeOnEsc: true }); var modal2 = new CMS.Modal({ minHeight: 300, minWidth: 100 }); expect(modal2.options).toEqual({ onClose: false, minHeight: 300, minWidth: 100, modalDuration: 200, resizable: true, maximizable: true, minimizable: true, closeOnEsc: true }); done(); }); }); }); describe('.open()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Messages = { open: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal(); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('throws an error when no url or html options were passed', function() { spyOn(modal, '_loadIframe'); expect(modal.open.bind(modal)).toThrowError(Error, 'The arguments passed to "open" were invalid.'); expect(modal.open.bind(modal, {})).toThrowError(Error, 'The arguments passed to "open" were invalid.'); expect(modal.open.bind(modal, { html: '' })).toThrowError( Error, 'The arguments passed to "open" were invalid.' ); expect(modal.open.bind(modal, { url: '' })).toThrowError( Error, 'The arguments passed to "open" were invalid.' ); expect(modal.open.bind(modal, { html: '
' })).not.toThrow(); expect( modal.open.bind(modal, { url: '/cms/tests/frontend/unit/html/modal_iframe.html' }) ).not.toThrow(); }); it('should be chainable', function() { expect(modal.open({ html: '
' })).toEqual(modal); }); it('hides the tooltip', function() { modal.open({ html: '
' }); expect(CMS.API.Tooltip.hide).toHaveBeenCalled(); }); it('triggers load events via helpers', function() { jasmine.clock().install(); spyOn(Helpers, 'dispatchEvent'); modal.open({ html: '
' }); expect(Helpers.dispatchEvent).toHaveBeenCalledWith( 'modal-load', jasmine.objectContaining({ instance: modal }) ); jasmine.clock().tick(modal.options.duration); expect(Helpers.dispatchEvent).toHaveBeenCalledWith( 'modal-loaded', jasmine.objectContaining({ instance: modal }) ); jasmine.clock().uninstall(); }); it('applies correct state to modal controls 1', function() { modal.open({ html: '
' }); // here and in others we cannot use `.toBeVisible` matcher, // because it uses jQuery's `:visible` selector which relies // on an element having offsetWidth/offsetHeight, but // Safari reports it to be 0 if an element is scaled with transform expect(modal.ui.resize).toHaveCss({ display: 'block' }); expect(modal.ui.minimizeButton).toHaveCss({ display: 'block' }); expect(modal.ui.maximizeButton).toHaveCss({ display: 'block' }); }); it('applies correct state to modal controls 2', function() { modal = new CMS.Modal({ resizable: false }); modal.open({ html: '
' }); expect(modal.ui.resize).toHaveCss({ display: 'none' }); expect(modal.ui.minimizeButton).toHaveCss({ display: 'block' }); expect(modal.ui.maximizeButton).toHaveCss({ display: 'block' }); }); it('applies correct state to modal controls 3', function() { modal = new CMS.Modal({ resizable: true }); modal.open({ html: '
' }); expect(modal.ui.resize).toHaveCss({ display: 'block' }); expect(modal.ui.minimizeButton).toHaveCss({ display: 'block' }); expect(modal.ui.maximizeButton).toHaveCss({ display: 'block' }); }); it('applies correct state to modal controls 4', function() { modal = new CMS.Modal({ minimizable: false }); modal.open({ html: '
' }); expect(modal.ui.resize).toHaveCss({ display: 'block' }); expect(modal.ui.minimizeButton).toHaveCss({ display: 'none' }); expect(modal.ui.maximizeButton).toHaveCss({ display: 'block' }); }); it('applies correct state to modal controls 5', function() { modal = new CMS.Modal({ minimizable: true }); modal.open({ html: '
' }); expect(modal.ui.resize).toHaveCss({ display: 'block' }); expect(modal.ui.minimizeButton).toHaveCss({ display: 'block' }); expect(modal.ui.maximizeButton).toHaveCss({ display: 'block' }); }); it('applies correct state to modal controls 6', function() { modal = new CMS.Modal({ maximizable: false }); modal.open({ html: '
' }); expect(modal.ui.resize).toHaveCss({ display: 'block' }); expect(modal.ui.minimizeButton).toHaveCss({ display: 'block' }); expect(modal.ui.maximizeButton).toHaveCss({ display: 'none' }); }); it('applies correct state to modal controls 7', function() { modal = new CMS.Modal({ maximizable: true }); modal.open({ html: '
' }); expect(modal.ui.resize).toHaveCss({ display: 'block' }); expect(modal.ui.minimizeButton).toHaveCss({ display: 'block' }); expect(modal.ui.maximizeButton).toHaveCss({ display: 'block' }); }); it('resets minimized state if the modal was already minimized', function() { modal.open({ html: '
' }); modal.minimize(); expect(modal.minimized).toEqual(true); spyOn(modal, 'minimize').and.callThrough(); modal.open({ html: '' }); expect(modal.minimized).toEqual(false); expect(modal.minimize).toHaveBeenCalled(); expect(modal.minimize.calls.count()).toEqual(1); }); it('clears breadcrumbs and buttons if they exist', function() { modal.ui.modal.addClass('cms-modal-has-breadcrumb'); modal.ui.modalButtons.html('
button
'); modal.ui.breadcrumb.html('
breadcrumbs
'); modal.open({ html: '
' }); expect(modal.ui.modal).not.toHaveClass('cms-modal-has-breadcrumb'); expect(modal.ui.modalButtons).toBeEmpty(); expect(modal.ui.breadcrumb).toBeEmpty(); }); }); describe('.minimize()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal(); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('minimizes the modal', function() { expect(modal.minimized).toEqual(false); modal.open({ html: '
' }); modal.minimize(); expect(modal.minimized).toEqual(true); expect(modal.ui.body).toHaveClass('cms-modal-minimized'); expect(modal.ui.modal).toHaveCss({ left: '50px' }); modal.minimize(); // restore }); it('stores the css data to be able to restore a modal', function() { modal.open({ html: '
' }); modal.minimize(); var css = modal.ui.modal.data('css'); expect(css).toEqual(jasmine.any(Object)); expect(Object.keys(css)).toContain('margin-left'); expect(Object.keys(css)).toContain('margin-top'); expect(Object.keys(css)).toContain('top'); expect(Object.keys(css)).toContain('left'); modal.minimize(); // restore }); it('does not minimize maximized modal', function() { modal.maximized = true; expect(modal.minimize()).toEqual(false); expect(CMS.API.Toolbar.open).not.toHaveBeenCalled(); expect(modal.ui.body).not.toHaveClass('cms-modal-minimized'); }); it('restores modal if it was already minimized', function() { modal.open({ html: '
' }); modal.minimize(); expect(modal.minimized).toEqual(true); expect(modal.ui.body).toHaveClass('cms-modal-minimized'); modal.minimize(); expect(modal.minimized).toEqual(false); expect(modal.ui.modal).toHaveCss(modal.ui.modal.data('css')); expect(modal.ui.body).not.toHaveClass('cms-modal-minimized'); }); }); describe('.maximize()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal(); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); modal.close(); fixture.cleanup(); }); it('maximizes the modal', function() { modal.open({ html: '
' }); modal.maximize(); expect(modal.ui.body).toHaveClass('cms-modal-maximized'); expect(modal.maximized).toEqual(true); modal.maximize(); // restore }); it('stores the css data to be able to restore a modal', function() { modal.open({ html: '
' }); modal.maximize(); var css = modal.ui.modal.data('css'); expect(css).toEqual(jasmine.any(Object)); expect(Object.keys(css)).toContain('margin-left'); expect(Object.keys(css)).toContain('margin-top'); expect(Object.keys(css)).toContain('width'); expect(Object.keys(css)).toContain('height'); expect(Object.keys(css)).toContain('top'); expect(Object.keys(css)).toContain('left'); modal.maximize(); // restore }); it('dispatches the modal-maximized event', function(done) { modal.open({ html: '
' }); CMS._eventRoot = $('#cms-top'); Helpers.addEventListener('modal-maximized', function(e, data) { Helpers.removeEventListener('modal-maximized'); expect(data.instance).toEqual(modal); done(); }); modal.maximize(); modal.maximize(); // restore }); it('does not maximize minimized modal', function() { modal.open({ html: '
' }); modal.minimize(); expect(modal.maximize()).toEqual(false); expect(modal.maximized).toEqual(false); expect(modal.minimized).toEqual(true); modal.minimize(); // restore }); it('restores modal if it was already maximized', function() { modal.open({ html: '
' }); modal.maximize(); modal.maximize(); // restore expect(modal.ui.body).not.toHaveClass('cms-modal-maximized'); expect(modal.ui.modal).toHaveCss(modal.ui.modal.data('css')); expect(modal.maximized).toEqual(false); }); it('dispatches modal-restored event when it restores the modal', function(done) { modal.open({ html: '
' }); CMS._eventRoot = $('#cms-top'); Helpers.addEventListener('modal-restored', function(e, data) { Helpers.removeEventListener('modal-restored'); expect(true).toEqual(true); expect(data.instance).toEqual(modal); done(); }); modal.maximize(); modal.maximize(); // restore }); }); describe('.close()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('returns false if modal-close event is prevented', function() { CMS._eventRoot = $('#cms-top'); Helpers.addEventListener('modal-close', function(e, opts) { e.preventDefault(); expect(opts.instance).toEqual(modal); }); spyOn(modal, '_hide').and.callThrough(); modal.open({ html: '
' }); expect(modal.close()).toEqual(false); expect(modal._hide).not.toHaveBeenCalled(); Helpers.removeEventListener('modal-close'); }); it('removes content preserving handlers', function() { var removeEventListener = jasmine.createSpy(); spyOn(Helpers, '_getWindow').and.returnValue({ removeEventListener: removeEventListener }); modal.open({ html: '
' }); modal.close(); expect(removeEventListener).toHaveBeenCalledTimes(1); expect(removeEventListener).toHaveBeenCalledWith('beforeunload', modal._beforeUnloadHandler); }); it('closes the modal', function(done) { modal.open({ html: '
' }); spyOn(modal, '_hide').and.callThrough(); setTimeout(function() { modal.close(); expect(modal._hide).toHaveBeenCalled(); setTimeout(function() { expect(modal.ui.modal).not.toHaveClass('cms-modal-open'); expect(modal.ui.modal).toHaveCss({ display: 'none' }); done(); }, 10); }, 10); }); it('reloads the browser if onClose is provided', function(done) { modal = new CMS.Modal({ onClose: '/this-url' }); modal.open({ html: '
' }); spyOn(Helpers, 'reloadBrowser').and.callFake(function(url, timeout) { expect(url).toEqual('/this-url'); expect(timeout).toEqual(false); done(); }); modal.close(); }); }); describe('._events()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); spyOn(modal, 'minimize'); spyOn(modal, 'maximize'); spyOn(modal, '_startMove'); spyOn(modal, '_startResize'); spyOn(modal, 'close'); spyOn(modal, '_changeIframe'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('attaches new events', function() { expect(modal.ui.minimizeButton).not.toHandle(modal.click); expect(modal.ui.minimizeButton).not.toHandle(modal.touchEnd); expect(modal.ui.maximizeButton).not.toHandle(modal.click); expect(modal.ui.maximizeButton).not.toHandle(modal.touchEnd); expect(modal.ui.title).not.toHandle(modal.pointerDown.split(' ')[0]); expect(modal.ui.title).not.toHandle(modal.pointerDown.split(' ')[1]); expect(modal.ui.title).not.toHandle(modal.doubleClick); expect(modal.ui.resize).not.toHandle(modal.pointerDown.split(' ')[0]); expect(modal.ui.resize).not.toHandle(modal.pointerDown.split(' ')[1]); expect(modal.ui.closeAndCancel).not.toHandle(modal.click); expect(modal.ui.closeAndCancel).not.toHandle(modal.touchEnd); expect(modal.ui.breadcrumb).not.toHandle(modal.click); modal._events(); expect(modal.ui.minimizeButton).toHandle(modal.click); expect(modal.ui.minimizeButton).toHandle(modal.touchEnd); expect(modal.ui.maximizeButton).toHandle(modal.click); expect(modal.ui.maximizeButton).toHandle(modal.touchEnd); expect(modal.ui.title).toHandle(modal.pointerDown.split(' ')[0]); expect(modal.ui.title).toHandle(modal.pointerDown.split(' ')[1]); expect(modal.ui.title).toHandle(modal.doubleClick); expect(modal.ui.resize).toHandle(modal.pointerDown.split(' ')[0]); expect(modal.ui.resize).toHandle(modal.pointerDown.split(' ')[1]); expect(modal.ui.closeAndCancel).toHandle(modal.click); expect(modal.ui.closeAndCancel).toHandle(modal.touchEnd); expect(modal.ui.breadcrumb).toHandle(modal.click); }); it('removes previous events', function() { var spy = jasmine.createSpy(); modal.ui.breadcrumb.html(''); modal.ui.minimizeButton.on(modal.click + ' ' + modal.touchEnd, spy); modal.ui.maximizeButton.on(modal.click + ' ' + modal.touchEnd, spy); modal.ui.title.on(modal.pointerDown + ' ' + modal.doubleClick, spy); modal.ui.resize.on(modal.pointerDown, spy); modal.ui.closeAndCancel.on(modal.click + ' ' + modal.touchEnd, spy); modal.ui.breadcrumb.on(modal.click, 'a', spy); modal._events(); modal.ui.minimizeButton.trigger(modal.click); modal.ui.minimizeButton.trigger(modal.touchEnd); modal.ui.maximizeButton.trigger(modal.click); modal.ui.maximizeButton.trigger(modal.touchEnd); modal.ui.title.trigger(modal.pointerDown.split(' ')[0]); modal.ui.title.trigger(modal.pointerDown.split(' ')[1]); modal.ui.title.trigger(modal.doubleClick); modal.ui.resize.trigger(modal.pointerDown.split(' ')[0]); modal.ui.resize.trigger(modal.pointerDown.split(' ')[1]); modal.ui.closeAndCancel.trigger(modal.click); modal.ui.closeAndCancel.trigger(modal.touchEnd); modal.ui.breadcrumb.find('a').trigger(modal.click); expect(spy).not.toHaveBeenCalled(); }); it('calls correct methods', function() { modal.ui.breadcrumb.html(''); modal._events(); modal.ui.minimizeButton.trigger(modal.click); modal.ui.minimizeButton.trigger(modal.touchEnd); expect(modal.minimize.calls.count()).toEqual(2); modal.ui.maximizeButton.trigger(modal.click); modal.ui.maximizeButton.trigger(modal.touchEnd); expect(modal.maximize.calls.count()).toEqual(2); modal.ui.title.trigger(modal.pointerDown.split(' ')[0]); modal.ui.title.trigger(modal.pointerDown.split(' ')[1]); expect(modal._startMove.calls.count()).toEqual(2); modal.ui.title.trigger(modal.doubleClick); expect(modal.maximize.calls.count()).toEqual(3); modal.ui.resize.trigger(modal.pointerDown.split(' ')[0]); modal.ui.resize.trigger(modal.pointerDown.split(' ')[1]); expect(modal._startResize.calls.count()).toEqual(2); modal.ui.closeAndCancel.trigger(modal.click); modal.ui.closeAndCancel.trigger(modal.touchEnd); expect(modal.close.calls.count()).toEqual(2); modal.ui.breadcrumb.find('a').trigger(modal.click); expect(modal._changeIframe.calls.count()).toEqual(1); }); }); describe('_calculateNewPosition()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); $('html').removeClass('cms-modal-maximized'); modal.ui.window = $('
').prependTo(fixture.el); // have to show the modal so the css values can be retrieved modal.ui.modal.show(); modal.ui.modal.addClass('cms-modal-open'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('fits the modal to the screen if there is enough space', function() { spyOn($.fn, 'css').and.returnValue(0); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: 1000, left: 1000 }); $.fn.css.and.callThrough(); modal.ui.window.css({ width: 1500, height: 1500 }); $.fn.css.and.returnValue(0); expect(modal._calculateNewPosition({})).toEqual({ width: 1200, height: 1200, top: 750, left: 750 }); }); it('respects params', function() { modal.ui.window.css({ width: 900, height: 500 }); // so it resets to middle of the screen spyOn($.fn, 'css').and.returnValue(0); expect( modal._calculateNewPosition({ width: 300, height: 300 }) ).toEqual({ width: 300, height: 300, top: 250, left: 450 }); expect( modal._calculateNewPosition({ width: 1000, height: 500 }) ).toEqual({ width: 1000, height: 500, top: 250, left: 450 }); }); it('respects minWidth and minHeight', function() { modal.ui.window.css({ width: 900, height: 500 }); // so it resets to middle of the screen spyOn($.fn, 'css').and.returnValue(0); expect(modal._calculateNewPosition({})).toEqual({ width: 800, height: 400, top: 250, left: 450 }); }); it('handles 50% left and top position case', function() { spyOn($.fn, 'css').and.returnValue('50%'); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: undefined, left: undefined }); }); it('moves modal to the middle of the screen if it does not fit the screen', function() { spyOn($.fn, 'css').and.returnValue(850); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: undefined, left: undefined }); $.fn.css.and.returnValue(2000 - 850); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: undefined, left: undefined }); $.fn.css.and.callFake(function(prop) { return { left: 850, top: 2000 - 850 }[prop]; }); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: undefined, left: undefined }); $.fn.css.and.callFake(function(prop) { return { left: 2000 - 850, top: 850 }[prop]; }); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: undefined, left: undefined }); $.fn.css.and.callFake(function(prop) { return { left: 849, top: 849 }[prop]; }); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: 1000, left: 1000 }); $.fn.css.and.callFake(function(prop) { return { left: 2000 - 849, top: 2000 - 849 }[prop]; }); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: 1000, left: 1000 }); $.fn.css.and.callFake(function(prop) { return { left: 849, top: 2000 - 849 }[prop]; }); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: 1000, left: 1000 }); $.fn.css.and.callFake(function(prop) { return { left: 2000 - 849, top: 849 }[prop]; }); expect(modal._calculateNewPosition({})).toEqual({ width: 1700, height: 1700, top: 1000, left: 1000 }); }); it('maximizes the modal if it goes out of the screen', function() { expect(modal.triggerMaximized).not.toEqual(true); modal.ui.window.css({ width: 900, height: 500 }); // so it resets to middle of the screen spyOn($.fn, 'css').and.returnValue(0); expect(modal._calculateNewPosition({})).toEqual({ width: 800, height: 400, top: 250, left: 450 }); expect(modal.triggerMaximized).not.toEqual(true); expect(modal._calculateNewPosition({ width: 900 })).toEqual({ width: 900, height: 400, top: 250, left: 450 }); expect(modal.triggerMaximized).toEqual(true); modal.triggerMaximized = false; expect(modal._calculateNewPosition({ height: 500 })).toEqual({ width: 800, height: 500, top: 250, left: 450 }); expect(modal.triggerMaximized).toEqual(true); }); }); describe('_show()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); spyOn(modal, 'maximize'); spyOn(modal, 'close'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('add morphing class if modal is already open', function(done) { modal.ui.modal.show(); expect(modal.ui.modal).not.toHaveClass('cms-modal-morphing'); expect(modal.ui.modal).not.toHaveClass('cms-modal-open'); modal.ui.modal.addClass('cms-modal-open'); modal.ui.modal.one('cmsTransitionEnd', function() { setTimeout(function() { expect(modal.ui.modal).not.toHaveClass('cms-modal-morphing'); done(); }, 0); }); modal._show({}); expect(modal.ui.modal).toHaveClass('cms-modal-morphing'); }); it('positions modal by given params', function(done) { spyOn($.fn, 'css'); modal.ui.modal.one('cmsTransitionEnd', function() { setTimeout(function() { expect($.fn.css).toHaveBeenCalledWith({ 'margin-left': -10, 'margin-top': -1.5 }); done(); }, 0); }); modal._show({ width: 20, height: 3, top: 123, left: 456 }); expect($.fn.css).toHaveBeenCalledWith({ display: 'block', width: 20, height: 3, top: 123, left: 456, 'margin-left': -10, 'margin-top': -1.5 }); }); it('maximizes the modal if required', function(done) { modal.ui.modal.one('cmsTransitionEnd', function() { setTimeout(function() { expect(modal.maximize).toHaveBeenCalled(); done(); }, 0); }); modal.triggerMaximized = true; modal._show({}); }); it('does not maximize the modal if not required', function(done) { modal.ui.modal.one('cmsTransitionEnd', function() { setTimeout(function() { expect(modal.maximize).not.toHaveBeenCalled(); done(); }, 0); }); modal.triggerMaximized = false; modal._show({}); }); it('triggers cms-modal-shown', function(done) { spyOn(Helpers, 'dispatchEvent'); modal.ui.modal.one('cmsTransitionEnd', function() { setTimeout(function() { expect(Helpers.dispatchEvent).toHaveBeenCalledWith( 'modal-shown', jasmine.objectContaining({ instance: modal }) ); done(); }, 0); }); modal._show({}); }); it('adds an event handler to close the modal by pressing ESC', function() { var spy = jasmine.createSpy(); modal.ui.body.on('keydown.cms.close', spy); modal.options.onClose = 'stuff'; modal._show({}); var wrongEvent = new $.Event('keydown.cms.close', { keyCode: KEYS.SPACE }); modal.ui.body.trigger(wrongEvent); expect(spy).not.toHaveBeenCalled(); expect(modal.close).not.toHaveBeenCalled(); expect(modal.options.onClose).toEqual('stuff'); var correctEvent = new $.Event('keydown.cms.close', { keyCode: KEYS.ESC }); modal.ui.body.trigger(correctEvent); expect(spy).not.toHaveBeenCalled(); expect(modal.close).toHaveBeenCalled(); expect(modal.options.onClose).toEqual(null); }); it('adds an event handler to close the modal by pressing ESC if closeOnEsc is set', function() { var spy = jasmine.createSpy(); modal.ui.body.on('keydown.cms.close', spy); modal.options.onClose = 'stuff'; modal.options.closeOnEsc = false; modal._show({}); var wrongEvent = new $.Event('keydown.cms.close', { keyCode: KEYS.SPACE }); modal.ui.body.trigger(wrongEvent); expect(spy).not.toHaveBeenCalled(); expect(modal.close).not.toHaveBeenCalled(); expect(modal.options.onClose).toEqual('stuff'); var correctEvent = new $.Event('keydown.cms.close', { keyCode: KEYS.ESC }); modal.ui.body.trigger(correctEvent); expect(spy).not.toHaveBeenCalled(); expect(modal.close).not.toHaveBeenCalled(); expect(modal.options.onClose).toEqual('stuff'); }); it('adds an event handler to close the modal by pressing ESC if confirmed', function() { var spy = jasmine.createSpy(); modal.ui.body.on('keydown.cms.close', spy); modal.options.onClose = 'stuff'; spyOn(modal, '_confirmDirtyEscCancel').and.returnValue(true); modal._show({}); var correctEvent = new $.Event('keydown.cms.close', { keyCode: KEYS.ESC }); modal.ui.body.trigger(correctEvent); expect(spy).not.toHaveBeenCalled(); expect(modal.close).toHaveBeenCalled(); expect(modal.options.onClose).toEqual(null); }); it('adds an event handler to not close the modal by pressing ESC if not confirmed', function() { var spy = jasmine.createSpy(); modal.ui.body.on('keydown.cms.close', spy); modal.options.onClose = 'stuff'; spyOn(modal, '_confirmDirtyEscCancel').and.returnValue(false); modal._show({}); var correctEvent = new $.Event('keydown.cms.close', { keyCode: KEYS.ESC }); modal.ui.body.trigger(correctEvent); expect(spy).not.toHaveBeenCalled(); expect(modal.close).not.toHaveBeenCalled(); expect(modal.options.onClose).toEqual('stuff'); }); it('focuses the modal', function() { spyOn($.fn, 'focus'); modal._show({}); expect($.fn.focus).toHaveBeenCalled(); expect($.fn.focus.calls.mostRecent().object).toEqual(modal.ui.modal); }); }); describe('_hide()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { jasmine.clock().install(); modal = new CMS.Modal({ modalDuration: 0 }); spyOn(modal, 'minimize'); spyOn(modal, 'maximize'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); jasmine.clock().uninstall(); }); it('empties the frame', function() { modal.ui.frame.html('
'); expect(modal.ui.frame).not.toBeEmpty(); modal._hide(); expect(modal.ui.frame).toBeEmpty(); }); it('removes loader', function() { modal.ui.modalBody.addClass('cms-loader'); expect(modal.ui.modalBody).toHaveClass('cms-loader'); modal._hide(); expect(modal.ui.modalBody).not.toHaveClass('cms-loader'); }); it('triggers cms-modal-closed', function() { spyOn(Helpers, 'dispatchEvent'); modal._hide({ duration: 10000000 }); expect(Helpers.dispatchEvent).not.toHaveBeenCalledWith( 'modal-closed', jasmine.objectContaining({ instance: modal }) ); jasmine.clock().tick(modal.options.duration); expect(Helpers.dispatchEvent).toHaveBeenCalledWith( 'modal-closed', jasmine.objectContaining({ instance: modal }) ); }); it('hides tooblar loader', function() { modal._hide({ duration: 10000000 }); jasmine.clock().tick(modal.options.duration); expect(hideLoader).toHaveBeenCalled(); }); it('resets minimize state', function() { modal.minimized = true; modal._hide(); expect(modal.minimize).not.toHaveBeenCalled(); jasmine.clock().tick(modal.options.duration); expect(modal.minimize).toHaveBeenCalled(); }); it('resets maximize state', function() { modal.maximized = true; modal._hide(); expect(modal.maximize).not.toHaveBeenCalled(); jasmine.clock().tick(modal.options.duration); expect(modal.maximize).toHaveBeenCalled(); }); it('removes the handler to close by ESC', function() { var spy = jasmine.createSpy(); modal.ui.body.on('keydown.cms.close', spy); expect(modal.ui.body).toHandle('keydown.cms.close'); modal._hide(); expect(modal.ui.body).not.toHandle('keydown.cms.close'); modal.ui.body.trigger('keydown.cms.close'); expect(spy).not.toHaveBeenCalled(); }); }); describe('_startMove()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); modal.ui.modal.show(); spyOn(modal, '_stopMove'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); document.body.style.touchAction = ''; modal.ui.body.off(modal.pointerMove); modal.ui.body.off(modal.pointerUp); fixture.cleanup(); }); it('returns false if modal is maximized', function() { modal.maximized = true; expect(modal._startMove()).toEqual(false); }); it('returns false if modal is minimized', function() { modal.minimized = true; expect(modal._startMove()).toEqual(false); }); it('shows the shim', function() { expect(modal.ui.shim).not.toBeVisible(); modal._startMove(); expect(modal.ui.shim).toBeVisible(); }); it('adds stopMove handler', function() { modal._startMove(); modal.ui.body.trigger(modal.pointerUp.split(' ')[0]); expect(modal._stopMove).toHaveBeenCalled(); modal.ui.body.trigger(modal.pointerUp.split(' ')[1]); expect(modal._stopMove).toHaveBeenCalledTimes(2); }); it('adds mousemove handler that repositions the modal', function(done) { var event = new $.Event(modal.pointerMove, { originalEvent: { pageX: 23, pageY: 28 } }); spyOn($.fn, 'position').and.returnValue({ left: 20, top: 30 }); spyOn($.fn, 'css').and.callFake(function(props) { if ( props && typeof props.left !== 'undefined' && typeof props.top !== 'undefined' && Object.keys(props).length === 2 ) { expect(props).toEqual({ left: 20 - (100 - 23), top: 30 - (100 - 28) }); done(); } }); modal._startMove({ originalEvent: { pageX: 100, pageY: 100 } }); setTimeout(function() { modal.ui.body.trigger(event); }, 1000); }); it('sets touchAction style property', function() { expect(document.body.style.touchAction).toEqual(''); modal._startMove(); expect(document.body.style.touchAction).toEqual('none'); }); }); describe('_stopMove()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); modal.ui.modal.show(); modal._startMove(); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('hides the shim', function() { expect(modal.ui.shim).toBeVisible(); modal._stopMove(); expect(modal.ui.shim).not.toBeVisible(); }); it('removes event handlers', function() { expect(modal.ui.body).toHandle(modal.pointerMove); expect(modal.ui.body).toHandle(modal.pointerUp.split(' ')[0]); expect(modal.ui.body).toHandle(modal.pointerUp.split(' ')[1]); modal._stopMove(); expect(modal.ui.body).not.toHandle(modal.pointerMove); expect(modal.ui.body).not.toHandle(modal.pointerUp.split(' ')[0]); expect(modal.ui.body).not.toHandle(modal.pointerUp.split(' ')[1]); }); it('resets touchAction style property', function() { document.body.style.touchAction = 'none'; modal._stopMove(); expect(document.body.style.touchAction).toEqual(''); }); }); describe('_startResize()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); modal.ui.modal.show(); spyOn(modal, '_stopResize'); spyOn(modal, 'close'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); document.body.style.touchAction = ''; modal.ui.body.off(modal.pointerMove); modal.ui.body.off(modal.pointerUp); fixture.cleanup(); }); it('returns false if the modal is maximized', function() { modal.maximized = true; expect(modal._startResize()).toEqual(false); }); it('shows the shim', function() { expect(modal.ui.shim).not.toBeVisible(); modal._startResize(); expect(modal.ui.shim).toBeVisible(); }); it('adds handler for pointermove to reposition the modal', function() { expect(modal.ui.body).not.toHandle(modal.pointerMove); modal._startResize(); expect(modal.ui.body).toHandle(modal.pointerMove); }); it('does not let the modal to be resized smaller than min height or min width', function(done) { var events = [ new $.Event(modal.pointerMove, { originalEvent: { pageX: 900, pageY: 900 } }), new $.Event(modal.pointerMove, { originalEvent: { pageX: 950, pageY: 700 } }), new $.Event(modal.pointerMove, { originalEvent: { pageX: 999, pageY: 999 } }) ]; modal.ui.modal.hide(); spyOn($.fn, 'width').and.returnValue(1000); spyOn($.fn, 'height').and.returnValue(1000); spyOn($.fn, 'show'); spyOn($.fn, 'position').and.returnValue({ left: 0, top: 0 }); modal._startResize({ originalEvent: { pageX: 1000, pageY: 1000 } }); var eventsHappened = 0; spyOn($.fn, 'css').and.callFake(function(props) { switch (eventsHappened) { case 0: { expect(props).toEqual({ width: 1000 - 100 * 2, height: 1000 - 100 * 2, left: 100, top: 100 }); break; } case 1: { expect(props).toEqual({ width: 1000 - 50 * 2, height: 1000 - 300 * 2, left: 50, top: 300 }); break; } case 2: { expect(props).toEqual({ width: 1000 - 1 * 2, height: 1000 - 1 * 2, left: 1, top: 1 }); done(); break; } default: { // do nothing } } eventsHappened++; }); events.forEach(function(event) { modal.ui.body.trigger(event); }); }); it('adds handler for pointerup to stop resizing', function() { expect(modal.ui.body).not.toHandle(modal.pointerUp.split(' ')[0]); expect(modal.ui.body).not.toHandle(modal.pointerUp.split(' ')[1]); modal._startResize(); expect(modal.ui.body).toHandle(modal.pointerUp.split(' ')[0]); expect(modal.ui.body).toHandle(modal.pointerUp.split(' ')[1]); modal.ui.body.trigger(modal.pointerUp.split(' ')[0]); modal.ui.body.trigger(modal.pointerUp.split(' ')[1]); expect(modal._stopResize).toHaveBeenCalledTimes(2); }); it('sets touchAction style property', function() { expect(document.body.style.touchAction).toEqual(''); modal._startResize(); expect(document.body.style.touchAction).toEqual('none'); }); }); describe('_stopResize()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); modal.ui.modal.show(); modal._startResize(); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('hides the shim', function() { expect(modal.ui.shim).toBeVisible(); modal._stopResize(); expect(modal.ui.shim).not.toBeVisible(); }); it('removes event handlers', function() { expect(modal.ui.body).toHandle(modal.pointerMove); expect(modal.ui.body).toHandle(modal.pointerUp.split(' ')[0]); expect(modal.ui.body).toHandle(modal.pointerUp.split(' ')[1]); modal._stopResize(); expect(modal.ui.body).not.toHandle(modal.pointerMove); expect(modal.ui.body).not.toHandle(modal.pointerUp.split(' ')[0]); expect(modal.ui.body).not.toHandle(modal.pointerUp.split(' ')[1]); }); it('resets touchAction style property', function() { document.body.style.touchAction = 'none'; modal._stopResize(); expect(document.body.style.touchAction).toEqual(''); }); }); describe('_setBreadcrumb()', function() { var modal; var validBreadcrumbs = [ { title: 'first', url: '#first' }, { title: 'second', url: '#second' }, { title: 'last', url: '#last' } ]; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); modal.ui.modal.show(); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('returns false if there is no breadcrumbs', function() { expect(modal._setBreadcrumb()).toEqual(false); }); it('returns false if there is only one breadcrumb', function() { expect(modal._setBreadcrumb([])).toEqual(false); expect(modal._setBreadcrumb([{}])).toEqual(false); }); it('returns false if first breadcrumb does not have title', function() { expect(modal._setBreadcrumb([{}, { title: 'breadcrumb', url: '#' }])).toEqual(false); }); it('adds class to the modal', function() { expect(modal.ui.modal).not.toHaveClass('cms-modal-has-breadcrumb'); modal._setBreadcrumb(validBreadcrumbs); expect(modal.ui.modal).toHaveClass('cms-modal-has-breadcrumb'); }); it('creates appropriate markup for breadcrumbs', function() { expect(modal.ui.breadcrumb.html()).toEqual(''); modal._setBreadcrumb(validBreadcrumbs); // depending on the browser classes can be in different places or // not exist at all expect(modal.ui.breadcrumb.html()).toMatch( new RegExp( [ 'first', 'second', 'last' ].join('') ) ); }); it('makes last breadcrumb active', function() { modal._setBreadcrumb(validBreadcrumbs); expect(modal.ui.breadcrumb.find('a:last')).toHaveClass('active'); }); }); describe('_setButtons()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.config = { lang: { cancel: 'Cancel!' } }; CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); modal.ui.modal.show(); spyOn(modal, '_loadIframe'); spyOn(modal, 'close'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('renders buttons from the iframe to the modal', function() { expect(modal.ui.modalButtons).toBeEmpty(); modal._setButtons($('.buttons-test-iframe')); expect(modal.ui.modalButtons).not.toBeEmpty(); expect(modal.ui.modalButtons.html()).toMatch( new RegExp( [ '
', '
', 'default', '
', '
', 'whatever correct', '
', '
', 'link', '
', '
', 'caution', '
', '
', 'Cancel!', '
', '
' ].join('') ) ); }); it('adds handlers to the newly created buttons', function() { modal._setButtons($('.buttons-test-iframe')); expect(modal.ui.modalButtons.find('a')).toHandle(modal.click); expect(modal.ui.modalButtons.find('a')).toHandle(modal.touchEnd); var spy = jasmine.createSpy(); spyOn($.fn, 'hide'); $('.buttons-test-iframe').find('a, input, button').on('click', function(e) { e.preventDefault(); spy(); }); modal.ui.modalButtons.find('.cms-modal-item-buttons:eq(2) a').trigger(modal.click); expect(modal._loadIframe).toHaveBeenCalledWith({ url: jasmine.stringMatching(/cms_path[^#]*?#go/), name: 'link' }); expect(spy).not.toHaveBeenCalled(); expect(modal.saved).toEqual(false); expect(modal.hideFrame).toEqual(undefined); modal.ui.modalButtons.find('.cms-modal-item-buttons:eq(0) a').trigger(modal.touchEnd); expect(spy).toHaveBeenCalledTimes(1); expect(modal.saved).toEqual(false); expect(modal.hideFrame).toEqual(true); modal.saved = false; modal.hideFrame = undefined; modal.ui.modalButtons.find('.cms-modal-item-buttons:eq(1) a').trigger(modal.touchEnd); expect(spy).toHaveBeenCalledTimes(2); expect(modal.saved).toEqual(false); expect(modal.hideFrame).toEqual(undefined); expect($.fn.hide).not.toHaveBeenCalled(); modal.saved = false; modal.hideFrame = undefined; modal.ui.modalButtons.find('.cms-modal-item-buttons:eq(3) a').trigger(modal.touchEnd); expect(spy).toHaveBeenCalledTimes(2); expect(modal.saved).toEqual(true); expect(modal.hideFrame).toEqual(undefined); expect($.fn.hide.calls.mostRecent().object.selector).toEqual( modal.ui.modal.find('.cms-modal-frame iframe').selector ); modal.saved = false; modal.hideFrame = undefined; modal.options = { onClose: 'something' }; expect(modal.close).not.toHaveBeenCalled(); modal.ui.modalButtons.find('.cms-modal-item-buttons:eq(4) a').trigger(modal.click); expect(spy).toHaveBeenCalledTimes(2); expect(modal.saved).toEqual(false); expect(modal.hideFrame).toEqual(undefined); expect(modal.close).toHaveBeenCalled(); expect(modal.options.onClose).toEqual(null); expect($.fn.hide).toHaveBeenCalledTimes(1); }); it('submits the form vs clicking on button if there is only one submit button', function() { $('.buttons-test-iframe').find('input, a').remove(); modal._setButtons($('.buttons-test-iframe')); var clickSpy = jasmine.createSpy(); var submitSpy = jasmine.createSpy(); $('.buttons-test-iframe').find('button').on('click', function(e) { e.preventDefault(); clickSpy(); }); $('#iframe-form').on('submit', function(e) { e.preventDefault(); submitSpy(); }); modal.ui.modalButtons.find('.cms-modal-item-buttons:eq(0) a').trigger(modal.click); expect(clickSpy).not.toHaveBeenCalled(); expect(submitSpy).toHaveBeenCalledTimes(1); }); it('adds submit handlers to the form', function() { modal._setButtons($('.buttons-test-iframe')); var form = $('#iframe-form').on('submit', function(e) { e.preventDefault(); }); expect(modal.saved).toEqual(false); expect(modal.hideFrame).toEqual(undefined); form.trigger('submit'); expect(modal.saved).toEqual(false); expect(modal.hideFrame).toEqual(undefined); modal.hideFrame = true; form.trigger('submit'); expect(modal.saved).toEqual(true); expect(modal.hideFrame).toEqual(true); }); }); describe('_changeIframe()', function() { var modal; var breadcrumbs = [ { title: 'first', url: '#first' }, { title: 'second', url: '#second' }, { title: 'last', url: '#last' } ]; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal({ modalDuration: 0 }); modal.ui.modal.show(); modal._setBreadcrumb(breadcrumbs); spyOn(modal, '_loadIframe'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('returns false if element was active', function() { expect(modal._changeIframe(modal.ui.breadcrumb.find('a:last'))).toEqual(false); }); it('changes the class if element was not active', function() { expect(modal.ui.breadcrumb.find('a:last')).toHaveClass('active'); modal._changeIframe(modal.ui.breadcrumb.find('a:first')); expect(modal.ui.breadcrumb.find('a:last')).not.toHaveClass('active'); expect(modal.ui.breadcrumb.find('a:first')).toHaveClass('active'); }); it('loads the iframe', function() { modal._changeIframe(modal.ui.breadcrumb.find('a:first')); expect(modal._loadIframe).toHaveBeenCalledWith({ url: '#first' }); }); it('changes titlePrefix', function() { expect(modal.ui.titlePrefix.text()).toEqual(''); modal._changeIframe(modal.ui.breadcrumb.find('a:eq(1)')); expect(modal.ui.titlePrefix.text()).toEqual('second'); }); }); describe('CMS.Modal._setupCtrlEnterSave()', function() { var spy; var button; var doc = $(document); beforeEach(function(done) { fixture.load('modal.html'); $(function() { spy = jasmine.createSpy(); button = $('
').on('click', spy); button.appendTo('.cms-modal-buttons'); done(); }); }); afterEach(function() { doc.off('keydown.cms.submit keyup.cms.submit'); fixture.cleanup(); }); it('adds handlers to the document', function() { expect(doc).not.toHandle('keydown.cms.submit'); expect(doc).not.toHandle('keyup.cms.submit'); CMS.Modal._setupCtrlEnterSave(document); expect(doc).toHandle('keydown.cms.submit'); expect(doc).toHandle('keyup.cms.submit'); }); it('triggers modal action if ctrl+enter is pressed on win', function() { spyOn(String.prototype, 'toLowerCase').and.returnValue('win'); CMS.Modal._setupCtrlEnterSave(document); doc.trigger(new $.Event('keydown', { ctrlKey: false, keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { ctrlKey: false, keyCode: KEYS.ENTER })); expect(spy).not.toHaveBeenCalled(); doc.trigger(new $.Event('keydown', { ctrlKey: true, keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { ctrlKey: true, keyCode: KEYS.ENTER })); expect(spy).toHaveBeenCalledTimes(1); }); it('does not trigger modal action if ctrl+enter is pressed on mac', function() { spyOn(String.prototype, 'toLowerCase').and.returnValue('mac'); CMS.Modal._setupCtrlEnterSave(document); doc.trigger(new $.Event('keydown', { ctrlKey: false, keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { ctrlKey: false, keyCode: KEYS.ENTER })); expect(spy).not.toHaveBeenCalled(); doc.trigger(new $.Event('keydown', { ctrlKey: true, keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { ctrlKey: true, keyCode: KEYS.ENTER })); expect(spy).not.toHaveBeenCalled(); }); it('triggers modal action if cmd+enter is pressed on mac', function() { spyOn(String.prototype, 'toLowerCase').and.returnValue('mac'); CMS.Modal._setupCtrlEnterSave(document); doc.trigger(new $.Event('keydown', { keyCode: KEYS.CMD_LEFT })); doc.trigger(new $.Event('keydown', { keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.CMD_LEFT })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.ENTER })); expect(spy).toHaveBeenCalledTimes(1); doc.trigger(new $.Event('keydown', { keyCode: KEYS.CMD_RIGHT })); doc.trigger(new $.Event('keydown', { keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.CMD_RIGHT })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.ENTER })); expect(spy).toHaveBeenCalledTimes(2); doc.trigger(new $.Event('keydown', { keyCode: KEYS.CMD_FIREFOX })); doc.trigger(new $.Event('keydown', { keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.CMD_FIREFOX })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.ENTER })); expect(spy).toHaveBeenCalledTimes(3); }); it('does not trigger modal action if cmd enter was pressed on mac through subsequent keystrokes', function() { spyOn(String.prototype, 'toLowerCase').and.returnValue('mac'); CMS.Modal._setupCtrlEnterSave(document); doc.trigger(new $.Event('keydown', { keyCode: KEYS.CMD_LEFT })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.CMD_LEFT })); doc.trigger(new $.Event('keydown', { keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.ENTER })); expect(spy).not.toHaveBeenCalled(); doc.trigger(new $.Event('keydown', { keyCode: KEYS.CMD_RIGHT })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.CMD_RIGHT })); doc.trigger(new $.Event('keydown', { keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.ENTER })); expect(spy).not.toHaveBeenCalled(); doc.trigger(new $.Event('keydown', { keyCode: KEYS.CMD_FIREFOX })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.CMD_FIREFOX })); doc.trigger(new $.Event('keydown', { keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.ENTER })); expect(spy).not.toHaveBeenCalled(); }); it('does not trigger modal action if cmd+enter is pressed on win', function() { spyOn(String.prototype, 'toLowerCase').and.returnValue('win'); CMS.Modal._setupCtrlEnterSave(document); doc.trigger(new $.Event('keydown', { keyCode: KEYS.CMD_LEFT })); doc.trigger(new $.Event('keydown', { keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.CMD_LEFT })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.ENTER })); expect(spy).not.toHaveBeenCalled(); doc.trigger(new $.Event('keydown', { keyCode: KEYS.CMD_RIGHT })); doc.trigger(new $.Event('keydown', { keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.CMD_RIGHT })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.ENTER })); expect(spy).not.toHaveBeenCalled(); doc.trigger(new $.Event('keydown', { keyCode: KEYS.CMD_FIREFOX })); doc.trigger(new $.Event('keydown', { keyCode: KEYS.ENTER })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.CMD_FIREFOX })); doc.trigger(new $.Event('keyup', { keyCode: KEYS.ENTER })); expect(spy).not.toHaveBeenCalled(); }); }); describe('_loadIframe()', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Messages = { open: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; $(function() { modal = new CMS.Modal(); modal.ui.modal.show(); spyOn(Helpers, 'reloadBrowser'); spyOn(modal, '_setBreadcrumb'); spyOn(modal, '_setButtons'); spyOn(CMS.Modal, '_setupCtrlEnterSave'); spyOn(modal, 'close'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('adds appropriate classes', function() { jasmine.clock().install(); expect(modal.ui.modal).not.toHaveClass('cms-modal-iframe'); expect(modal.ui.modal).not.toHaveClass('cms-modal-markup'); expect(modal.ui.modalBody).not.toHaveClass('cms-loader'); modal.ui.modal.addClass('cms-modal-markup'); modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe.html' }); expect(modal.ui.modal).toHaveClass('cms-modal-iframe'); expect(modal.ui.modal).not.toHaveClass('cms-modal-markup'); expect(modal.ui.modalBody).not.toHaveClass('cms-loader'); jasmine.clock().tick(501); expect(modal.ui.modalBody).toHaveClass('cms-loader'); jasmine.clock().uninstall(); }); it('adds correct title while loading', function() { expect(modal.ui.titlePrefix.text()).toEqual(''); expect(modal.ui.titleSuffix.text()).toEqual(''); modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe.html' }); expect(modal.ui.titlePrefix.text()).toEqual(''); expect(modal.ui.titleSuffix.text()).toEqual(''); modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe.html', title: 'Test title' }); expect(modal.ui.titlePrefix.text()).toEqual('Test title'); expect(modal.ui.titleSuffix.text()).toEqual(''); }); it('opens error message and closes the iframe if its contents cannot be accessed', function(done) { CMS.config.lang.errorLoadingEditForm = 'Cannot access contents'; spyOn($.fn, 'contents').and.callFake(function() { throw new Error('Cannot access contents'); }); modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.close).toHaveBeenCalled(); expect(CMS.API.Messages.open).toHaveBeenCalledWith({ message: 'Cannot access contents', error: true, delay: 0 }); done(); }); }); it('sets up ctrl + enter save', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(CMS.Modal._setupCtrlEnterSave).toHaveBeenCalledWith( modal.ui.frame.find('iframe')[0].contentDocument ); done(); }); }); it('shows and hides the loader', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe.html' }); expect(hideLoader).not.toHaveBeenCalled(); expect(showLoader).toHaveBeenCalledTimes(1); modal.ui.modal.find('iframe').on('load', function() { expect(hideLoader).toHaveBeenCalledTimes(1); expect(showLoader).toHaveBeenCalledTimes(1); done(); }); }); it('shows messages if iframe contains them', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(CMS.API.Messages.open).toHaveBeenCalledWith({ message: 'Django CMS is amazing!' }); done(); }); }); it('adds cms-admin cms-admin-modal classes to the iframe body', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect($(this).contents().find('body')).toHaveClass('cms-admin'); expect($(this).contents().find('body')).toHaveClass('cms-admin-modal'); done(); }); }); it('removes cms-loader class when iframe is loaded', function(done) { jasmine.clock().install(); modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); jasmine.clock().tick(501); expect(modal.ui.modalBody).toHaveClass('cms-loader'); modal.ui.modal.find('iframe').on('load', function() { expect(modal.ui.modalBody).not.toHaveClass('cms-loader'); jasmine.clock().uninstall(); done(); }); }); describe('reloading', function() { it('does not reload the page if not required', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(Helpers.reloadBrowser).not.toHaveBeenCalled(); done(); }); }); it('does not reload the page if not required', function(done) { modal.enforceReload = true; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(Helpers.reloadBrowser).not.toHaveBeenCalled(); done(); }); }); xit('does reload the page if required', function(done) { modal.enforceReload = true; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(Helpers.reloadBrowser).toHaveBeenCalledWith(); done(); }); }); xit('does show loaders if reload the page if required', function(done) { modal.enforceReload = true; expect(modal.ui.modalBody).not.toHaveClass('cms-loader'); modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(showLoader).toHaveBeenCalledTimes(2); expect(modal.ui.modalBody).toHaveClass('cms-loader'); done(); }); }); }); it('does not close the modal if not required', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.close).not.toHaveBeenCalled(); done(); }); }); it('does not close the modal if not required', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.close).not.toHaveBeenCalled(); done(); }); }); it('does not close the modal if not required', function(done) { modal.enforceClose = true; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.close).not.toHaveBeenCalled(); done(); }); }); it('closes the modal if required', function(done) { modal.enforceClose = true; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.close).toHaveBeenCalledTimes(1); done(); }); }); it('resets django viewsitelink to open in the top level window', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.close).not.toHaveBeenCalled(); expect($(this).contents().find('.viewsitelink')).toHaveAttr('target', '_top'); done(); }); }); it('sets the buttons', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal._setButtons).toHaveBeenCalledWith($(this)); done(); }); }); it('does not reset the saved state if there is no form errors', function(done) { modal.saved = 'custom'; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.saved).toEqual('custom'); done(); }); }); it('resets the saved state if there is a form error loaded in the iframe', function(done) { modal.saved = true; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_errornote.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.saved).toEqual(false); done(); }); }); it('resets the saved state if there was no success message in the frame', function(done) { modal.saved = true; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_no_success.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.saved).toEqual(false); done(); }); }); it('resets the saved state if there is a form error loaded in the iframe', function(done) { modal.saved = true; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_errorlist.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.saved).toEqual(false); done(); }); }); xit('reloads browser if iframe was saved and there is no delete confirmation', function(done) { modal.saved = true; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(Helpers.reloadBrowser).toHaveBeenCalledWith(jasmine.any(String)); done(); }); }); xit('reloads browser if iframe was saved and there is no delete confirmation', function(done) { modal.saved = true; modal.options.onClose = '/custom-on-close'; modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(Helpers.reloadBrowser).toHaveBeenCalledWith('/custom-on-close'); done(); }); }); xit('shows loaders when reloads browser if iframe was saved', function(done) { modal.saved = true; expect(modal.ui.modalBody).not.toHaveClass('cms-loader'); modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(showLoader).toHaveBeenCalledTimes(1); expect(modal.ui.modalBody).toHaveClass('cms-loader'); done(); }); }); it('updates the title of the modal if required', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_title.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.ui.titlePrefix.text()).toEqual('I am a title'); expect(modal.ui.titleSuffix.text()).toEqual(''); expect($(this).contents().find('h1').length).toEqual(1); done(); }); }); it('updates the title of the modal if required', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_title.html', title: 'Test title' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.ui.titlePrefix.text()).toEqual('Test title'); expect(modal.ui.titleSuffix.text()).toEqual('I am a title'); expect($(this).contents().find('h1').length).toEqual(1); done(); }); }); it('updates the title of the modal if required', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_title.html', title: ' ' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal.ui.titlePrefix.text()).toEqual('I am a title'); expect(modal.ui.titleSuffix.text()).toEqual(''); expect($(this).contents().find('h1').length).toEqual(1); done(); }); }); it('sets iframe data ready', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_title.html' }); expect(modal.ui.frame.find('iframe').data('ready')).toEqual(undefined); modal.ui.modal.find('iframe').on('load', function() { expect($(this).data('ready')).toEqual(true); done(); }); }); it('adds keydown event to close the modal if ESC is pressed inside of the iframe', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_title.html' }); modal.ui.modal.find('iframe').on('load', function() { var body = $(this).contents().find('body'); expect(body).toHandle('keydown.cms'); body.on('keydown.cms', function() { if (modal.close.calls.count()) { // have to wait till next frame here // because Edge is too fast and it cleans up // the test case _before_ second trigger call finishes setTimeout(function() { done(); }, 0); } }); body.trigger(new $.Event('keydown', { keyCode: KEYS.SPACE })); body.trigger(new $.Event('keydown', { keyCode: KEYS.ESC })); }); }); it('adds keydown event that does not close if not confirmed', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_title.html' }); spyOn(modal, '_confirmDirtyEscCancel').and.returnValue(false); modal.ui.modal.find('iframe').on('load', function() { var body = $(this).contents().find('body'); expect(body).toHandle('keydown.cms'); body.on('keydown.cms', function() { expect(modal._confirmDirtyEscCancel).toHaveBeenCalledTimes(1); expect(modal.close).not.toHaveBeenCalled(); done(); }); body.trigger(new $.Event('keydown', { keyCode: KEYS.ESC })); }); }); it('does not adjust content if object-tools are not available', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_messages.html' }); spyOn($.fn, 'css'); modal.ui.modal.find('iframe').on('load', function() { expect($.fn.css).not.toHaveBeenCalledWith('padding-top', 38); done(); }); }); it('does not adjust content if object-tools are available', function(done) { modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_title.html' }); spyOn($.fn, 'css'); modal.ui.modal.find('iframe').on('load', function() { expect($.fn.css).not.toHaveBeenCalledWith('padding-top', 38); done(); }); }); it('attaches content preserving handlers', function(done) { spyOn(modal, '_attachContentPreservingHandlers'); modal._loadIframe({ url: '/cms/tests/frontend/unit/html/modal_iframe_title.html' }); modal.ui.modal.find('iframe').on('load', function() { expect(modal._attachContentPreservingHandlers).toHaveBeenCalledTimes(1); expect(modal._attachContentPreservingHandlers).toHaveBeenCalledWith(this); done(); }); }); }); describe('_attachContentPreservingHandlers', function() { var modal; beforeEach(function(done) { fixture.load('modal.html'); CMS.API.Tooltip = { hide: jasmine.createSpy() }; CMS.API.Messages = { open: jasmine.createSpy() }; CMS.API.Toolbar = { open: jasmine.createSpy() }; CMS.config = { lang: { confirmDirty: 'Smth changed!', confirmDirtyESC: 'Smth changed and you are pressing ESC' } }; $(function() { modal = new CMS.Modal(); modal.ui.modal.show(); spyOn(Helpers, 'reloadBrowser'); spyOn(modal, '_setBreadcrumb'); spyOn(modal, '_setButtons'); spyOn(CMS.Modal, '_setupCtrlEnterSave'); spyOn(modal, 'close'); done(); }); }); afterEach(function() { window.removeEventListener('beforeunload', modal._beforeUnloadHandler); fixture.cleanup(); }); it('creates the tracker', function() { expect(modal.tracker).not.toBeDefined(); modal._attachContentPreservingHandlers($()); expect(modal.tracker).toEqual(jasmine.any(Object)); }); it('adds the evnet listener to the window', function() { var addEventListener = jasmine.createSpy(); spyOn(Helpers, '_getWindow').and.returnValue({ addEventListener: addEventListener }); modal._attachContentPreservingHandlers($()); expect(addEventListener).toHaveBeenCalledTimes(1); expect(addEventListener).toHaveBeenCalledWith('beforeunload', modal._beforeUnloadHandler); }); describe('_beforeUnloadHandler', function() { it('returns a warning if form has changed', function() { modal.tracker = { isFormChanged: function() { return true; } }; expect(modal._beforeUnloadHandler({})).toEqual('Smth changed!'); }); it('assigns return value to the event if form has changed', function() { modal.tracker = { isFormChanged: function() { return true; } }; var event = {}; modal._beforeUnloadHandler(event); expect(event.returnValue).toEqual('Smth changed!'); }); it('does not do anything if form did not change', function() { modal.tracker = { isFormChanged: function() { return false; } }; expect(modal._beforeUnloadHandler({})).not.toBeDefined(); }); }); describe('_confirmDirtyEscCancel', function() { beforeEach(function() { spyOn(Helpers, 'secureConfirm'); }); it('returns true if there is no tracker', function() { expect(modal._confirmDirtyEscCancel()).toEqual(true); expect(Helpers.secureConfirm).not.toHaveBeenCalled(); }); it('returns true if there is a tracker but form did not change', function() { modal.tracker = { isFormChanged: function() { return false; } }; expect(modal._confirmDirtyEscCancel()).toEqual(true); expect(Helpers.secureConfirm).not.toHaveBeenCalled(); }); it('returns result of the confirmation if there is a tracker and form changed', function() { Helpers.secureConfirm.and.returnValue(true); modal.tracker = { isFormChanged: function() { return true; } }; expect(modal._confirmDirtyEscCancel()).toEqual(true); expect(Helpers.secureConfirm).toHaveBeenCalledTimes(1); expect(Helpers.secureConfirm).toHaveBeenCalledWith( 'Smth changed!\n\nSmth changed and you are pressing ESC' ); Helpers.secureConfirm.and.returnValue(false); expect(modal._confirmDirtyEscCancel()).toEqual(false); expect(Helpers.secureConfirm).toHaveBeenCalledTimes(2); }); }); }); });