describe 'up.popup', -> u = up.util describe 'Javascript functions', -> describe 'up.popup.attach', -> beforeEach -> jasmine.addMatchers toSitBelow: (util, customEqualityTesters) -> compare: ($popup, $link) -> popupDims = $popup.get(0).getBoundingClientRect() linkDims = $link.get(0).getBoundingClientRect() pass: Math.abs(popupDims.right - linkDims.right) < 1.0 && Math.abs(popupDims.top - linkDims.bottom) < 1.0 beforeEach -> @restoreBodyHeight = u.temporaryCss('body', 'min-height': '3000px') afterEach -> @restoreBodyHeight() it "loads this link's destination in a popup positioned under the given link", -> $container = affix('.container') $container.css position: 'absolute' left: '100px' top: '50px' $link = $container.affix('a[href="/path/to"][up-popup=".middle"]').text('link') up.popup.attach($link) expect(@lastRequest().url).toMatch /\/path\/to$/ @respondWith """
new-before
new-middle
new-after
""" $popup = $('.up-popup') expect($popup).toExist() expect($popup.find('.middle')).toHaveText('new-middle') expect($popup.find('.before')).not.toExist() expect($popup.find('.after')).not.toExist() expect($popup.css('position')).toEqual('absolute') expect($popup).toSitBelow($link) it 'gives the popup { position: "fixed" } if the given link is fixed', -> # Let's test the harder case where the document is scrolled up.layout.scroll(document, 50) $container = affix('.container') $container.css position: 'fixed' left: '100px' top: '50px' $link = $container.affix('a[href="/path/to"][up-popup=".content"]').text('link') up.popup.attach($link) @respondWith('
popup-content
') $popup = $('.up-popup') expect($popup.css('position')).toEqual('fixed') expect($popup).toSitBelow($link) it 'does not explode if the popup was closed before the response was received', -> $span = affix('span') up.popup.attach($span, url: '/foo', target: '.container') up.popup.close() respond = => @respondWith('
text
') expect(respond).not.toThrowError() expect($('.up-error')).not.toExist() describe 'with { html } option', -> it 'extracts the selector from the given HTML string', (done) -> $span = affix('span') up.popup.attach($span, target: '.container', html: "
container contents
").then -> expect($('.up-popup')).toHaveText('container contents') done() describe 'opening a popup while another modal is open', -> describeCapability 'canCssTransition', -> it 'closes the current popup and wait for its close animation to finish before starting the open animation of a second popup', (done) -> $span = affix('span') up.popup.config.openAnimation = 'fade-in' up.popup.config.openDuration = 5 up.popup.config.closeAnimation = 'fade-out' up.popup.config.closeDuration = 50 events = [] u.each ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed'], (event) -> up.on event, -> events.push(event) up.popup.attach($span, { target: '.target', html: '
response1
' }) # First popup is starting opening animation expect(events).toEqual ['up:popup:open'] expect($('.target')).toHaveText('response1') u.setTimer 30, -> # First popup has completed opening animation expect(events).toEqual ['up:popup:open', 'up:popup:opened'] expect($('.target')).toHaveText('response1') up.popup.attach($span, { target: '.target', html: '
response2
' }) u.setTimer 15, -> # Second popup is still waiting for first popup's closing animation to finish. expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:close'] expect($('.target')).toHaveText('response1') u.setTimer 100, -> # First popup has finished closing, second popup has finished opening. expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed', 'up:popup:open', 'up:popup:opened'] expect($('.target')).toHaveText('response2') done() describe 'up.popup.coveredUrl', -> describeCapability 'canPushState', -> it 'returns the URL behind the popup', (done) -> up.history.replace('/foo') expect(up.popup.coveredUrl()).toBeMissing() $popupLink = affix('a[href="/bar"][up-popup=".container"][up-history="true"]') $popupLink.click() @respondWith('
text
') expect(up.popup.coveredUrl()).toEndWith('/foo') up.popup.close().then -> expect(up.popup.coveredUrl()).toBeMissing() done() describe 'up.popup.close', -> it 'should have tests' describe 'up.popup.source', -> it 'should have tests' describe 'unobtrusive behavior', -> describe 'a[up-popup]', -> beforeEach -> @stubAttach = => @$link = affix('a[href="/path"][up-popup=".target"]') @attachSpy = up.popup.knife.mock('attachAsap').and.returnValue(u.resolvedPromise()) @defaultSpy = up.link.knife.mock('allowDefault').and.callFake((event) -> event.preventDefault()) it 'opens the clicked link in a popup', -> @stubAttach() Trigger.click(@$link) expect(@attachSpy).toHaveBeenCalledWith(@$link) # IE does not call Javascript and always performs the default action on right clicks unless navigator.userAgent.match(/Trident/) it 'does nothing if the right mouse button is used', -> @stubAttach() Trigger.click(@$link, button: 2) expect(@attachSpy).not.toHaveBeenCalled() it 'does nothing if shift is pressed during the click', -> @stubAttach() Trigger.click(@$link, shiftKey: true) expect(@attachSpy).not.toHaveBeenCalled() it 'does nothing if ctrl is pressed during the click', -> @stubAttach() Trigger.click(@$link, ctrlKey: true) expect(@attachSpy).not.toHaveBeenCalled() it 'does nothing if meta is pressed during the click', -> @stubAttach() Trigger.click(@$link, metaKey: true) expect(@attachSpy).not.toHaveBeenCalled() it 'closes an existing popup before opening the new popup', -> up.popup.config.openDuration = 0 up.popup.config.closeDuration = 0 $link1 = affix('a[href="/path1"][up-popup=".target"]') $link2 = affix('a[href="/path2"][up-popup=".target"]') events = [] u.each ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed'], (event) -> up.on event, -> events.push(event) Trigger.click($link1) expect(events).toEqual ['up:popup:open'] @respondWith('
text1
') expect(events).toEqual ['up:popup:open', 'up:popup:opened'] Trigger.click($link2) expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed', 'up:popup:open'] @respondWith('
text1
') expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed', 'up:popup:open', 'up:popup:opened'] describe 'with [up-instant] modifier', -> beforeEach -> @stubAttach() @$link.attr('up-instant', '') it 'opens the modal on mousedown (instead of on click)', -> Trigger.mousedown(@$link) expect(@attachSpy.calls.mostRecent().args[0]).toEqual(@$link) it 'does nothing on mouseup', -> Trigger.mouseup(@$link) expect(@attachSpy).not.toHaveBeenCalled() it 'does nothing on click', -> Trigger.click(@$link) expect(@attachSpy).not.toHaveBeenCalled() # IE does not call Javascript and always performs the default action on right clicks unless navigator.userAgent.match(/Trident/) it 'does nothing if the right mouse button is pressed down', -> Trigger.mousedown(@$link, button: 2) expect(@attachSpy).not.toHaveBeenCalled() it 'does nothing if shift is pressed during mousedown', -> Trigger.mousedown(@$link, shiftKey: true) expect(@attachSpy).not.toHaveBeenCalled() it 'does nothing if ctrl is pressed during mousedown', -> Trigger.mousedown(@$link, ctrlKey: true) expect(@attachSpy).not.toHaveBeenCalled() it 'does nothing if meta is pressed during mousedown', -> Trigger.mousedown(@$link, metaKey: true) expect(@attachSpy).not.toHaveBeenCalled() describe 'with [up-method] modifier', -> it 'honours the given method', -> $link = affix('a[href="/path"][up-popup=".target"][up-method="post"]') Trigger.click($link) expect(@lastRequest().method).toEqual 'POST' describe '[up-close]', -> describe 'when clicked inside a popup', -> it 'closes the open popup and prevents the default action', (done) -> $link = affix('a') up.popup.attach($link, html: '
text
', target: '.target').then -> $popup = affix('.up-popup') $link = $popup.affix('a[up-close]') # link is within the popup up.hello($link) wasDefaultPrevented = false wasClosed = false up.on 'click', 'a[up-close]', (event) -> wasDefaultPrevented = event.isDefaultPrevented() true # the line above might return false and cancel propagation / prevent default up.on 'up:popup:close', -> wasClosed = true $link.click() u.nextFrame -> expect(wasClosed).toBe(true) expect(wasDefaultPrevented).toBe(true) done() describe 'when no popup is open', -> it 'does neither close the popup nor prevent the default action', -> $link = affix('a[up-close]') # link is outside the popup up.hello($link) wasDefaultPrevented = false wasClosed = false up.on 'click', 'a[up-close]', (event) -> wasDefaultPrevented = event.isDefaultPrevented() true # the line above might return false and cancel propagation / prevent default up.on 'up:popup:close', -> wasClosed = true $link.click() expect(wasClosed).toBe(false) expect(wasDefaultPrevented).toBe(false) describe 'when replacing content', -> beforeEach -> up.motion.config.enabled = false it 'prefers to replace a selector within the popup', -> $outside = affix('.foo').text('old outside') $link = affix('.link') up.popup.attach($link, target: '.foo') @respondWith("
old inside
") up.extract('.foo', "
new text
") expect($outside).toBeInDOM() expect($outside).toHaveText('old outside') expect($('.up-popup')).toHaveText('new text') it 'auto-closes the popup when a replacement from inside the popup affects a selector behind the popup', -> affix('.outside').text('old outside') $link = affix('.link') up.popup.attach($link, target: '.inside') @respondWith("
old inside
") up.extract('.outside', "
new outside
", origin: $('.inside')) expect($('.outside')).toHaveText('new outside') expect($('.up-popup')).not.toExist() it 'does not restore the covered URL when auto-closing', (done) -> up.motion.config.enabled = true up.popup.config.openDuration = 0 up.popup.config.closeDuration = 20 up.popup.config.history = true affix('.outside').text('old outside') $link = affix('.link') whenPopupOpen = up.popup.attach($link, url: '/path', target: '.inside') @respondWith("
old inside
") # Populate popup whenPopupOpen.then -> up.extract('.outside', "
new outside
", origin: $('.inside'), history: '/new-location') # Provoke auto-close u.setTimer 50, -> expect(location.href).toEndWith '/new-location' done() it 'does not auto-close the popup when a replacement from inside the popup affects a selector inside the popup', -> affix('.outside').text('old outside') $link = affix('.link') up.popup.attach($link, target: '.inside') @respondWith("
old inside
") up.extract('.inside', "
new inside
", origin: $('.inside')) expect($('.inside')).toHaveText('new inside') expect($('.up-popup')).toExist() it 'does not auto-close the popup when a replacement from outside the popup affects a selector outside the popup', -> affix('.outside').text('old outside') $link = affix('.link') up.popup.attach($link, target: '.inside') @respondWith("
old inside
") up.extract('.outside', "
new outside
", origin: $('.outside')) expect($('.outside')).toHaveText('new outside') expect($('.up-popup')).toExist() it 'does not auto-close the popup when a replacement from outside the popup affects a selector inside the popup', -> affix('.outside').text('old outside') $link = affix('.link') up.popup.attach($link, target: '.inside') @respondWith("
old inside
") up.extract('.inside', "
new inside
", origin: $('.outside')) expect($('.inside')).toHaveText('new inside') expect($('.up-popup')).toExist() describe 'when clicking on the body', -> beforeEach -> up.motion.config.enabled = false it 'closes a popup on mousedown (in case an [up-instant] link removes its parent and thus a click event never fires)', -> affix('.outside').text('old outside') $link = affix('.link') up.popup.attach($link, target: '.inside') @respondWith("
inside
") Trigger.mousedown($('body')) expect($('.up-popup')).not.toExist()