lib/assets/javascripts/up/modal.js.coffee in upjs-rails-0.8.0 vs lib/assets/javascripts/up/modal.js.coffee in upjs-rails-0.8.1
- old
+ new
@@ -11,42 +11,33 @@
###
up.modal = (->
u = up.util
- currentSource = undefined
-
- config =
- width: 'auto'
- height: 'auto'
- openAnimation: 'fade-in'
- closeAnimation: 'fade-out'
- closeLabel: 'X'
- template: (config) ->
- """
- <div class="up-modal">
- <div class="up-modal-dialog">
- <div class="up-modal-close" up-close>#{config.closeLabel}</div>
- <div class="up-modal-content"></div>
- </div>
- </div>
- """
-
###*
Sets default options for future modals.
@method up.modal.defaults
- @param {Number} [options.width='auto']
- The width of the dialog in pixels.
- Defaults to `'auto'`, meaning that the dialog will grow to fit its contents.
+ @param {Number} [options.width]
+ The width of the dialog as a CSS value like `'400px'` or `50%`.
+
+ Defaults to `undefined`, meaning that the dialog will grow to fit its contents
+ until it reaches `options.maxWidth`. Leaving this as `undefined` will
+ also allow you to control the width using CSS.
+ @param {Number} [options.maxWidth]
+ The width of the dialog as a CSS value like `'400px'` or `50%`.
+ You can set this to `undefined` to make the dialog fit its contents.
+ Be aware however, that e.g. Bootstrap stretches input elements
+ to `width: 100%`, meaning the dialog will also stretch to the full
+ width of the screen.
@param {Number} [options.height='auto']
The height of the dialog in pixels.
- Defaults to `'auto'`, meaning that the dialog will grow to fit its contents.
+ Defaults to `undefined`, meaning that the dialog will grow to fit its contents.
@param {String|Function(config)} [options.template]
A string containing the HTML structure of the modal.
You can supply an alternative template string, but make sure that it
- contains tags with the classes `up-modal`, `up-modal-dialog` and `up-modal-content`.
+ defines tag with the classes `up-modal`, `up-modal-dialog` and `up-modal-content`.
You can also supply a function that returns a HTML string.
The function will be called with the modal options (merged from these defaults
and any per-open overrides) whenever a modal opens.
@param {String} [options.closeLabel='X']
@@ -56,13 +47,35 @@
to both the dialog box and the overlay dimming the page.
@param {String} [options.closeAnimation='fade-out']
The animation used to close the modal. The animation will be applied
to both the dialog box and the overlay dimming the page.
###
- defaults = (options) ->
- u.extend(config, options)
-
+ config = u.config
+ maxWidth: undefined
+ minWidth: undefined
+ width: undefined
+ height: undefined
+ openAnimation: 'fade-in'
+ closeAnimation: 'fade-out'
+ closeLabel: '×'
+ template: (config) ->
+ """
+ <div class="up-modal">
+ <div class="up-modal-dialog">
+ <div class="up-modal-close" up-close>#{config.closeLabel}</div>
+ <div class="up-modal-content"></div>
+ </div>
+ </div>
+ """
+
+ currentSource = undefined
+
+ reset = ->
+ close()
+ currentSource = undefined
+ config.reset()
+
templateHtml = ->
template = config.template
if u.isFunction(template)
template(config)
else
@@ -76,29 +89,48 @@
discardHistory = ->
$popup = $('.up-modal')
$popup.removeAttr('up-previous-url')
$popup.removeAttr('up-previous-title')
- createHiddenModal = (selector, width, height, sticky) ->
+ createHiddenModal = (options) ->
$modal = $(templateHtml())
- $modal.attr('up-sticky', '') if sticky
+ $modal.attr('up-sticky', '') if options.sticky
$modal.attr('up-previous-url', up.browser.url())
$modal.attr('up-previous-title', document.title)
$dialog = $modal.find('.up-modal-dialog')
- $dialog.css('width', width) if u.isPresent(width)
- $dialog.css('height', height) if u.isPresent(height)
- $content = $dialog.find('.up-modal-content')
- $placeholder = u.$createElementFromSelector(selector)
+ $dialog.css('width', options.width) if u.isPresent(options.width)
+ $dialog.css('max-width', options.maxWidth) if u.isPresent(options.maxWidth)
+ $dialog.css('height', options.height) if u.isPresent(options.height)
+ $content = $modal.find('.up-modal-content')
+ $placeholder = u.$createElementFromSelector(options.selector)
$placeholder.appendTo($content)
$modal.appendTo(document.body)
rememberHistory()
$modal.hide()
$modal
+ unshiftBody = undefined
+
+ # Gives `<body>` a right padding in the width of a scrollbar.
+ # This is to prevent the body from jumping when we add the
+ # overlay, which has its own scroll bar.
+ shiftBody = ->
+ scrollbarWidth = u.scrollbarWidth()
+ bodyRightPadding = parseInt($('body').css('padding-right'))
+ bodyRightShift = scrollbarWidth + bodyRightPadding
+ unshiftBody = u.temporaryCss($('body'),
+ 'padding-right': "#{bodyRightShift}px",
+ 'overflow-y': 'hidden'
+ )
+
updated = ($modal, animation, animateOptions) ->
+ up.bus.emit('modal:open')
+ shiftBody()
$modal.show()
- up.animate($modal, animation, animateOptions)
+ promise = up.animate($modal, animation, animateOptions)
+ promise.then -> up.bus.emit('modal:opened')
+ promise
###*
Opens the given link's destination in a modal overlay:
var $link = $('...');
@@ -110,11 +142,18 @@
up.modal.open({ url: '/foo', target: '.list' })
This will request `/foo`, extract the `.list` selector from the response
and open the selected container in a modal dialog.
-
+
+ \#\#\#\# Events
+
+ - Emits an [event](/up.bus) `modal:open` when the modal
+ is starting to open.
+ - Emits an [event](/up.bus) `modal:opened` when the opening
+ animation has finished and the modal contents are fully visible.
+
@method up.modal.open
@param {Element|jQuery|String} [elementOrSelector]
The link to follow.
Can be omitted if you give `options.url` instead.
@param {String} [options.url]
@@ -154,18 +193,24 @@
options = u.options(options)
url = u.option(options.url, $link.attr('up-href'), $link.attr('href'))
selector = u.option(options.target, $link.attr('up-modal'), 'body')
width = u.option(options.width, $link.attr('up-width'), config.width)
+ maxWidth = u.option(options.maxWidth, $link.attr('up-max-width'), config.maxWidth)
height = u.option(options.height, $link.attr('up-height'), config.height)
animation = u.option(options.animation, $link.attr('up-animation'), config.openAnimation)
sticky = u.option(options.sticky, $link.is('[up-sticky]'))
history = if up.browser.canPushState() then u.option(options.history, $link.attr('up-history'), true) else false
animateOptions = up.motion.animateOptions(options, $link)
close()
- $modal = createHiddenModal(selector, width, height, sticky)
+ $modal = createHiddenModal
+ selector: selector
+ width: width
+ maxWidth: maxWidth
+ height: height
+ sticky: sticky
up.replace(selector, url,
history: history
insert: -> updated($modal, animation, animateOptions)
)
@@ -182,10 +227,17 @@
currentSource
###*
Closes a currently opened modal overlay.
Does nothing if no modal is currently open.
+
+ \#\#\#\# Events
+
+ - Emits an [event](/up.bus) `modal:close` when the modal
+ is starting to close.
+ - Emits an [event](/up.bus) `modal:closed` when the closing
+ animation has finished and the modal has been removed from the DOM.
@method up.modal.close
@param {Object} options
See options for [`up.animate`](/up.motion#up.animate)
###
@@ -196,11 +248,18 @@
animation: config.closeAnimation,
url: $modal.attr('up-previous-url')
title: $modal.attr('up-previous-title')
)
currentSource = undefined
- up.destroy($modal, options)
+ up.bus.emit('modal:close')
+ promise = up.destroy($modal, options)
+ promise.then ->
+ unshiftBody()
+ up.bus.emit('modal:closed')
+ promise
+ else
+ u.resolvedPromise()
autoclose = ->
unless $('.up-modal').is('[up-sticky]')
discardHistory()
close()
@@ -318,16 +377,15 @@
up.on('click', '[up-close]', (event, $element) ->
if $element.closest('.up-modal')
close()
)
- # The framework is reset between tests, so also close
- # a currently open modal dialog.
- up.bus.on 'framework:reset', close
+ # The framework is reset between tests
+ up.bus.on 'framework:reset', reset
open: open
close: close
source: source
- defaults: defaults
+ defaults: config.update
contains: contains
)()