$q = null LAYERS = [] LAYERS_BY_ID = {} CALLBACKS = {} INSTANCE = {} App.factory('Layers', ['$q',(q)-> $q = q createId = (-> possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; _id = '' _id += possible.charAt(Math.floor(Math.random() * possible.length)) for i in [0..20] return _id ) addLayer = (($element, should_fade_body)-> _id = createId() layer = { _id: _id, $element: $element, onRemove: ((callback)-> addLayerCallback(_id, callback) return layer ) remove: ((args...)-> removeLayer(_id, args...) return layer ) should_fade_body: should_fade_body } setTimeout(-> finishAddLayer(layer)) return layer ) addLayerCallback = ((_id, callback)-> CALLBACKS[_id] ||= [] CALLBACKS[_id].push(callback) if callback ) finishAddLayer = ((layer)-> LAYERS.unshift(layer) LAYERS_BY_ID[layer._id] = layer $('body').addClass('locked-scroll') if layer.should_fade_body layer.$element.attr('is-active-layer', 'true') ) removeLayer = ((_id, args...)-> layer = LAYERS_BY_ID[_id] return if !layer callbacks = CALLBACKS[_id] || [] callback(args...) for callback in callbacks delete CALLBACKS[_id] delete LAYERS_BY_ID[_id] for layer, i in LAYERS return if layer._id != _id layer_i_to_remove = i break LAYERS.splice(layer_i_to_remove, 1) $('body').removeClass('locked-scroll') if layer.should_fade_body layer.$element.attr('is-active-layer', 'false') ) removeAll = (-> removeLayer(layer._id) while layer = LAYERS.shift() ) ###################################################################################################################### $('body').on('click', (e)-> layer = LAYERS[0] return if !layer return if $(e.target).hasClass('dropdown-toggle') $target = $(e.target) return if !$.contains(document, $target[0]) $element = $target if $target.attr('is-active-layer') $element ||= $target.closest('[is-active-layer="true"]') return if ($element and $element.length and $element[0] == layer.$element[0]) layer.remove() ) $('body').on('keydown', (e)-> return if e.keyCode != 27 layer = LAYERS[0] return if !layer layer.remove() ) ###################################################################################################################### INSTANCE.add = ((element, should_fade_body=false)-> return addLayer($(element), should_fade_body) ) INSTANCE.removeAll = removeAll return INSTANCE; ]);