lib/assets/javascripts/unpoly/popup.js.coffee in unpoly-rails-0.24.1 vs lib/assets/javascripts/unpoly/popup.js.coffee in unpoly-rails-0.25.0

- old
+ new

@@ -3,11 +3,11 @@ =============== Instead of [linking to a page fragment](/up.link), you can choose to show a fragment in a popup overlay that rolls down from an anchoring element. -To open a popup, add an [`up-popup` attribute](/a-up-popup) to a link, +To open a popup, add an [`up-popup` attribute](/up-popup) to a link, or call the Javascript function [`up.popup.attach`](/up.popup.attach). For modal dialogs see [up.modal](/up.modal) instead. \#\#\#\# Customizing the popup design @@ -29,11 +29,11 @@ \#\#\#\# Closing behavior The popup closes when the user clicks anywhere outside the popup area. By default the popup also closes -*whenever a page fragment behind the popup is updated*. +*when a link within the popup changes a fragment behind the popup*. This is useful to have the popup interact with the page that opened it, e.g. by updating parts of a larger form or by signing in a user and revealing additional information. To disable this behavior, give the opening link an `up-sticky` attribute: @@ -69,25 +69,40 @@ ###* Sets default options for future popups. @property up.popup.config - @param {String} [config.openAnimation='fade-in'] - The animation used to open a popup. - @param {String} [config.closeAnimation='fade-out'] - The animation used to close a popup. @param {String} [config.position='bottom-right'] Defines where the popup is attached to the opening element. Valid values are `bottom-right`, `bottom-left`, `top-right` and `top-left`. @param {String} [config.history=false] Whether opening a popup will add a browser history entry. + @param {String} [config.openAnimation='fade-in'] + The animation used to open a popup. + @param {String} [config.closeAnimation='fade-out'] + The animation used to close a popup. + @param {String} [config.openDuration] + The duration of the open animation (in milliseconds). + @param {String} [config.closeDuration] + The duration of the close animation (in milliseconds). + @param {String} [config.openEasing] + The timing function controlling the acceleration of the opening animation. + @param {String} [config.closeEasing] + The timing function controlling the acceleration of the closing animation. + @param {Boolean} [options.sticky=false] + If set to `true`, the popup remains + open even it changes the page in the background. @stable ### config = u.config openAnimation: 'fade-in' closeAnimation: 'fade-out' + openDuration: null + closeDuration: null + openEasing: null + closeEasing: null position: 'bottom-right' history: false reset = -> close(animation: false) @@ -145,19 +160,24 @@ $popup = $('.up-popup') $popup.removeAttr('up-covered-url') $popup.removeAttr('up-covered-title') createFrame = (target, options) -> - $popup = u.$createElementFromSelector('.up-popup') - $popup.attr('up-sticky', '') if options.sticky - $popup.attr('up-covered-url', up.browser.url()) - $popup.attr('up-covered-title', document.title) - # Create an empty element that will match the - # selector that is being replaced. - u.$createPlaceholder(target, $popup) - $popup.appendTo(document.body) - $popup + promise = u.resolvedPromise() + if isOpen() + promise = promise.then -> close() + promise = promise.then -> + $popup = u.$createElementFromSelector('.up-popup') + $popup.attr('up-sticky', '') if options.sticky + $popup.attr('up-covered-url', up.browser.url()) + $popup.attr('up-covered-title', document.title) + # Create an empty element that will match the + # selector that is being replaced. + u.$createPlaceholder(target, $popup) + $popup.appendTo(document.body) + $popup + return promise ###* Returns whether popup modal is currently open. @function up.popup.isOpen @@ -172,10 +192,12 @@ Emits events [`up:popup:open`](/up:popup:open) and [`up:popup:opened`](/up:popup:opened). @function up.popup.attach @param {Element|jQuery|String} elementOrSelector @param {String} [options.url] + @param {String} [options.target] + A CSS selector that will be extracted from the response and placed into the popup. @param {String} [options.position='bottom-right'] Defines where the popup is attached to the opening element. Valid values are `bottom-right`, `bottom-left`, `top-right` and `top-left`. @param {String} [options.confirm] @@ -201,37 +223,39 @@ attach = (linkOrSelector, options) -> $link = $(linkOrSelector) $link.length or u.error('Cannot attach popup to non-existing element %o', linkOrSelector) options = u.options(options) - url = u.option(options.url, $link.attr('href')) - target = u.option(options.target, $link.attr('up-popup'), 'body') + url = u.option(u.pluckKey(options, 'url'), $link.attr('up-href'), $link.attr('href')) + html = u.option(u.pluckKey(options, 'html')) + target = u.option(u.pluckKey(options, 'target'), $link.attr('up-popup'), 'body') options.position = u.option(options.position, $link.attr('up-position'), config.position) options.animation = u.option(options.animation, $link.attr('up-animation'), config.openAnimation) - options.sticky = u.option(options.sticky, u.castedAttr($link, 'up-sticky')) + options.sticky = u.option(options.sticky, u.castedAttr($link, 'up-sticky'), config.sticky) options.history = if up.browser.canPushState() then u.option(options.history, u.castedAttr($link, 'up-history'), config.history) else false options.confirm = u.option(options.confirm, $link.attr('up-confirm')) - animateOptions = up.motion.animateOptions(options, $link) + animateOptions = up.motion.animateOptions(options, $link, duration: config.openDuration, easing: config.openEasing) up.browser.confirm(options).then -> if up.bus.nobodyPrevents('up:popup:open', url: url, message: 'Opening popup') - wasOpen = isOpen() - close(animation: false) if wasOpen options.beforeSwap = -> createFrame(target, options) - promise = up.replace(target, url, u.merge(options, animation: false)) + extractOptions = u.merge(options, animation: false) + if html + promise = up.extract(target, html, extractOptions) + else + promise = up.replace(target, url, extractOptions) promise = promise.then -> setPosition($link, options.position) - unless wasOpen - promise = promise.then -> - up.animate($('.up-popup'), options.animation, animateOptions) promise = promise.then -> + up.animate($('.up-popup'), options.animation, animateOptions) + promise = promise.then -> up.emit('up:popup:opened', message: 'Popup opened') promise else # Although someone prevented the destruction, keep a uniform API for - # callers by returning a Deferred that will never be resolved. - u.unresolvableDeferred() + # callers by returning a promise that will never be resolved. + u.unresolvablePromise() ###* This event is [emitted](/up.emit) when a popup is starting to open. @event up:popup:open @@ -255,11 +279,11 @@ Emits events [`up:popup:close`](/up:popup:close) and [`up:popup:closed`](/up:popup:closed). @function up.popup.close @param {Object} options See options for [`up.animate`](/up.animate). - @return {Deferred} + @return {Promise} A promise that will be resolved once the modal's close animation has finished. @stable ### close = (options) -> @@ -269,21 +293,22 @@ options = u.options(options, animation: config.closeAnimation, url: $popup.attr('up-covered-url'), title: $popup.attr('up-covered-title') ) + animateOptions = up.motion.animateOptions(options, duration: config.closeDuration, easing: config.closeEasing) + u.extend(options, animateOptions) currentUrl = undefined - deferred = up.destroy($popup, options) - deferred.then -> up.emit('up:popup:closed', message: 'Popup closed') - deferred + promise = up.destroy($popup, options) + promise = promise.then -> up.emit('up:popup:closed', message: 'Popup closed') + promise else - # Although someone prevented the destruction, - # keep a uniform API for callers by returning - # a Deferred that will never be resolved. - u.unresolvableDeferred() + # Although someone prevented the destruction, keep a uniform API + # for callers by returning a promise that will never be resolved. + u.unresolvablePromise() else - u.resolvedDeferred() + u.resolvedPromise() ###* This event is [emitted](/up.emit) when a popup dialog is starting to [close](/up.popup.close). @@ -327,10 +352,10 @@ if a page fragment behind the popup overlay updates: <a href="/decks" up-popup=".deck_list">Switch deck</a> <a href="/settings" up-popup=".options" up-sticky>Settings</a> - @selector a[up-popup] + @selector [up-popup] @param [up-position] Defines where the popup is attached to the opening element. Valid values are `bottom-right`, `bottom-left`, `top-right` and `top-left`. @param {String} [up-confirm]